目录
Please enable Javascript to view the contents

Docker 易错集锦 — ENTRYPOINT 中环境变量无法替换

 ·  ☕ 1 分钟

重要

ENTRYPOINT ["java", "$JAVA_OPTS", "-jar", "/app.jar"]$JAVA_OPTS 不会被替换。exec 格式不经过 shell,不支持变量展开。

1. 问题

不管 ENV JAVA_OPTS="-Xmx512m" 还是 docker run -e JAVA_OPTS="-Xmx1024m"ENTRYPOINT$JAVA_OPTS 始终是字面量。

2. 原因:exec vs shell

Dockerfile 的 ENTRYPOINT/RUN/CMD 有两种格式:

exec 格式shell 格式
写法CMD ["app", "--port=8080"]CMD app --port=8080
执行方式直接 exec,不经过 /bin/sh/bin/sh -c "app --port=8080"
变量展开不支持支持
PID 1命令自身/bin/sh,命令为其子进程
信号处理能收到 SIGTERM,可优雅启停SIGTERM 发给 /bin/sh,子进程收不到
适用场景ENTRYPOINT / CMDRUN

变量展开失败是因为 exec 格式不调用 shell,$JAVA_OPTS 永远不会被替换。

3. 解决

把 shell 逻辑放到脚本中,ENTRYPOINT 用 exec 格式调用脚本:

1
2
# start.sh
java $JAVA_OPTS -jar /app.jar
1
2
3
ENV JAVA_OPTS="-Xmx512m"
COPY start.sh /start.sh
ENTRYPOINT ["/bin/sh", "-c", "/start.sh"]

不推荐直接在 ENTRYPOINT 里内联 shell 命令(如 ENTRYPOINT ["/bin/sh", "-c", "java $JAVA_OPTS -jar /app.jar"]),因为 PID 1 变成 /bin/sh,容器内的 java 进程收不到 docker stop 的 SIGTERM,无法优雅退出。

4. 总结

场景推荐格式原因
RUNshell 格式需要 &&、管道、变量
ENTRYPOINT/CMDexec 格式 + 脚本PID 1 正确,信号可达
需要变量展开exec 格式 + 脚本变量在脚本内展开

参考

分享

Hex
作者
Hex
CloudNative Developer