在运行时将带有docker-compose.yml的ENV变量传递给Dockerfile

时间:2018-12-30 01:54:18

标签: docker docker-compose

我试图根据docker-compose.yml中的环境(dev / uat / prod)覆盖dockerfile中的ENV值。由于某些设置是敏感的,因此我无法将这些设置放在docker映像的构建步骤之外,因此必须在运行时覆盖这些值。我一直试图通过docker stack deploy -c命令部署以下docker-compose,但是我注意到我的环境变量没有覆盖dockerfile中的现有变量。

Dockerfile:

FROM openjdk:8-jdk-alpine
VOLUME /tmp
VOLUME /etc

ADD sample-0.0.1-SNAPSHOT.jar app.jar

ENV ENV_SETTINGS=ssldev
ENV ZK_HOST=zoo1
ENV JAVA_OPTS="-server -Xms6048m -Xmx6048m -XX:+UseParNewGC - XX:+UseConcMarkSweepGC -XX:+UseTLAB -XX:NewSize=128m -XX:MaxNewSize=128m - XX:MaxTenuringThreshold=0 -XX:SurvivorRatio=1024 - XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=40 - XX:MaxGCPauseMillis=1000 -XX:InitiatingHeapOccupancyPercent=50 - XX:+UseCompressedOops -XX:ParallelGCThreads=8 -XX:ConcGCThreads=8 - XX:+DisableExplicitGC -Dspring.profiles.active=${ENV_SETTINGS}"

EXPOSE 8080
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ]
HEALTHCHECK CMD curl --fail -k https://localhost:8080/status || exit 1

docker-compose.yml

version: '3.1'

services:
api:
    image: SOME_RANDOM_IMAGE
    ports:
        - "9083:8080"
    networks:
        - net
    deploy:
        restart_policy:
            condition: on-failure
        mode: global
    environment:
        - ENV_SETTINGS: default,ssldev,postgres
        - ZK_HOST: zoo1:2181,zoo2:2181
networks:
nsp_net:
  external:
    name: net

1 个答案:

答案 0 :(得分:0)

当您在Dockerfile中编写ENV语句时,docker build步骤将对其进行完全扩展,并在构建的映像中“放入”扩展值。 Docker没有提供在docker run时重新扩展环境变量的步骤。也就是说,您的问题不是未设置ENV_SETTINGS,而是未使用新的值JAVA_OPTS重新解释ENV_SETTINGS

要解决此问题,您可以提供一个设置环境的Shell脚本。我倾向于将图像分为两部分:

  1. 图像的ENTRYPOINT是一个脚本,用于设置环境变量并进行其他准备工作,并以exec "$@"结尾,以运行图像的CMD或传递给docker run的任何命令。
  2. 图像的CMD是您要运行的实际命令。

您的shell脚本可能如下所示:

#!/bin/sh
JAVA_OPTS="$JAVA_OPTS -Dspring.profiles.active=${ENV_SETTINGS:-ssldev}"
exec "$@"

相应的Dockerfile看起来像:

FROM openjdk:8-jdk-alpine
# Don't declare VOLUME of anything, especially not system directories.
# Prefer COPY to ADD.
COPY sample-0.0.1-SNAPSHOT.jar app.jar
# Should be executable (chmod +x) as checked into source control.
COPY entrypoint.sh entrypoint.sh

ENV ENV_SETTINGS=ssldev
ENV ZK_HOST=zoo1
# Don't include -Dspring.profiles.active here.
# Do include -Djava.security.egd here.
# The JVM knows about $JAVA_OPTS.
ENV JAVA_OPTS="-server -Xms6048m -Xmx6048m -XX:+UseParNewGC - XX:+UseConcMarkSweepGC -XX:+UseTLAB -XX:NewSize=128m -XX:MaxNewSize=128m - XX:MaxTenuringThreshold=0 -XX:SurvivorRatio=1024 - XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=40 - XX:MaxGCPauseMillis=1000 -XX:InitiatingHeapOccupancyPercent=50 - XX:+UseCompressedOops -XX:ParallelGCThreads=8 -XX:ConcGCThreads=8 - XX:+DisableExplicitGC -Djava.security.egd=file:/dev/./urandom"

EXPOSE 8080
ENTRYPOINT ["./entrypoint.sh"]
# Prefer quoted-word form.  But if you need a shell to process the
# command line, use unquoted form; don't explicitly "sh -c".
CMD ["java", "-jar", "app.jar"]
HEALTHCHECK CMD curl --fail -k https://localhost:8080/status || exit 1

(我总是更喜欢CMD而不是ENTRYPOINT:此包装器模式非常有用且无处不在,因此最好使其可用,并且docker run --rm -it imagename sh可以轻松获得交互式调试shell,如果您不必覆盖入口点以执行此操作。例外情况是,如果我正在构建FROM scratch图像,那么除了运行捆绑的二进制文件外,实际上什么都做不了,但这是一个例外。)

(还要注意,从Java 8的修补程序版本开始,较新的JVM可以选择满足容器的内存限制的选项,从而可以减小JAVA_OPTS设置;请参见“使JVM遵守CPU和RAM限制“在the openjdk image documentation上。)