
用 Dockerfile 定义自动化停机策略,核心不是让镜像“自己停自己”,而是为容器在外部触发停止(如 docker stop)时,提供可响应、可控制、可收敛的退出能力。真正的自动化停机逻辑必须由应用自身承载,Dockerfile 的作用是确保信号能传进去、进程能接住、清理能执行。
确保 PID 1 正确转发 SIGTERM
很多镜像失败的根源在于 shell 启动方式导致信号被拦截。比如:
-
❌ 错误写法(shell 形式):
CMD java -jar app.jar→ sh 作为 PID 1,不转发 SIGTERM 给子进程 -
✅ 正确写法(exec 形式):
CMD ["java", "-jar", "app.jar"]→ Java 进程直接成为 PID 1,可原生接收信号 -
? 兼容方案(需 shell 时):引入
tini作为轻量 init:RUN apk add --no-cache tiniENTRYPOINT ["/sbin/tini", "--"]CMD ["node", "server.js"]
嵌入可控的生命周期钩子
Dockerfile 本身不写业务逻辑,但可通过环境变量或启动参数把停机策略“注入”应用。例如:
- Java 应用:通过 JVM 参数或系统属性传递超时时间
CMD ["java", "-Dspring.lifecycle.timeout-per-shutdown-phase=45s", "-jar", "app.jar"] - Node.js 应用:用环境变量控制关闭等待窗口
ENV SHUTDOWN_TIMEOUT=30000CMD ["node", "server.js"](代码中读取process.env.SHUTDOWN_TIMEOUT) - Go 应用:通过构建时参数或运行时 flag 控制 graceful shutdown 窗口
配合运行时配置固化停机行为
Dockerfile 可声明默认行为,但最终生效依赖运行时参数。建议在镜像中预留可覆盖机制:
- 使用
STOPSIGNAL SIGTERM显式声明期望信号(虽默认就是 SIGTERM,但显式更清晰) - 通过
HEALTHCHECK配合停机逻辑:例如在收到 SIGTERM 后主动将健康检查返回 503,加速流量摘除HEALTHCHECK --interval=5s --timeout=2s CMD curl -f http://localhost/health || exit 1 - 避免在 Dockerfile 中硬编码
--stop-timeout(这是运行时参数),但可在 README 或 LABEL 中标注推荐值:LABEL org.opencontainers.image.description="建议 docker run --stop-timeout=60"
验证是否真正生效的实践要点
定义完 Dockerfile,必须验证信号链路和应用响应是否闭环:
- 启动容器后,进容器检查 PID 1 进程:
ps -p 1 -o comm=→ 应显示java/node,而非sh或bash - 手动发信号测试:
docker kill -s SIGTERM <id>,观察日志是否输出 “received SIGTERM”、“shutting down…” 等关键词 - 用
docker stop --time=5 <id>测试短超时,再用--time=60测试长超时,比对退出码:Exited (0)表示优雅退出;Exited (137)表示被 SIGKILL 强杀(说明超时或未响应)


















