我试图根据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
答案 0 :(得分:0)
当您在Dockerfile中编写ENV
语句时,docker build
步骤将对其进行完全扩展,并在构建的映像中“放入”扩展值。 Docker没有提供在docker run
时重新扩展环境变量的步骤。也就是说,您的问题不是未设置ENV_SETTINGS
,而是未使用新的值JAVA_OPTS
重新解释ENV_SETTINGS
。
要解决此问题,您可以提供一个设置环境的Shell脚本。我倾向于将图像分为两部分:
exec "$@"
结尾,以运行图像的CMD或传递给docker run
的任何命令。您的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上。)