docker - 在运行时使用 docker-compose.yml 将 ENV 变量传递给 Dockerfile
问题描述
我正在尝试根据 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
码头工人-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
解决方案
当您ENV
在 Dockerfile 中编写语句时,该docker build
步骤会完全扩展该语句并“烘焙”它构建的映像中的扩展值。Docker 没有提供将在docker run
时间重新扩展环境变量的步骤。也就是说,您的问题不是ENV_SETTINGS
没有被设置,而是JAVA_OPTS
没有被重新解释为ENV_SETTINGS
.
要解决此问题,您可以提供一个设置环境的 shell 脚本。我倾向于将需要此功能的图像分为两部分:
- 图像的 ENTRYPOINT 是一个脚本,它设置环境变量并进行其他准备工作,并
exec "$@"
以运行图像的 CMD 或传递给docker run
. - 图像的 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 可以选择遵守容器的内存限制,这会导致设置更小;请参阅openjdk 映像文档JAVA_OPTS
上的“使 JVM 尊重 CPU 和 RAM 限制” 。)
推荐阅读
- c++ - MinGW-w64 中的“get_s()”函数是什么
- java - UI 测试 - 断言排序数据 (Katalon/Selenium) Java
- c# - 测试自定义 JsonConverter 时出现异常
- java - Jboss(wildfly)中堆积的线程导致无响应
- javascript - 单选按钮处理程序中的代码似乎是错误的
- java - Intellij doExecute 未使用 DefaultProgramRunner 触发
- java - Java:哪个更好 - 返回一个 Object 属性或整个 Object
- javascript - React and Emotion (css):表格中的样式单元格
- javascript - 如何在 Angular 4+ 中使用 Fabric.js 在画布背景中设置图像大小
- wordpress - 使用 get_query_var (WordPress) 读取 URL 参数