核心是让容器主进程(PID 1)正确接收并响应 SIGTERM,以语义明确的退出码终止;Dockerfile 决定进程启动方式与信号可控性,需避免 shell 封装、显式声明 STOPSIGNAL,并配合应用内信号处理及 HEALTHCHECK 实现优雅退出与健康感知。

核心在于让容器主进程(PID 1)能正确接收、响应 SIGTERM,并在清理完成后以语义明确的退出码终止——Dockerfile 本身不执行“退出”,但它决定了进程如何启动、是否可被信号控制、以及退出后是否留下可诊断的状态。
确保主进程是 PID 1 并直接受控
Shell 封装会拦截信号,导致应用收不到 SIGTERM。必须避免 sh -c 或 bash -c 启动方式。
- ❌ 错误:CMD ["sh", "-c", "python app.py"] → shell 是 PID 1,python 是子进程,SIGTERM 发给 shell,不会自动转发
- ✅ 正确:CMD ["python", "app.py"] → python 直接成为 PID 1,可捕获 SIGTERM
- ✅ 更稳妥:ENTRYPOINT ["exec", "python"] && CMD ["app.py"] → exec 替换 shell 进程,彻底消除中间层
在应用中显式处理 SIGTERM(非 Dockerfile 编写,但必须配合)
Dockerfile 不写逻辑代码,但需为应用提供运行环境使其能响应信号。例如 Python 应用可这样处理:
- 监听 signal.SIGTERM,设置标志位或触发 shutdown 流程
- 等待正在处理的请求完成(如 HTTP server 的 graceful shutdown)
- 关闭数据库连接、刷新日志缓冲区、释放锁等
- 最后调用 sys.exit(0)(成功退出)或 sys.exit(1)(异常退出)
Go/Java/Node.js 等主流语言均有标准方式注册信号处理器,关键不是 Dockerfile 写什么,而是它启动的程序是否做了这件事。
通过 STOPSIGNAL 声明期望的终止信号
Dockerfile 中可用 STOPSIGNAL 明确告诉 Docker 使用哪个信号停止容器,默认是 SIGTERM,但显式声明更清晰、可维护。
- STOPSIGNAL SIGTERM —— 推荐写法,强调应用应响应此信号
- STOPSIGNAL SIGQUIT —— 极少数场景(如 Nginx),但需应用支持
- 不建议改用 SIGKILL:它不可捕获,等于放弃优雅退出能力
配合 HEALTHCHECK 提供运行时健康状态反馈
退出码只反映“是否结束”,无法说明“是否还能服务”。HEALTHCHECK 可独立判断服务可用性,辅助自动化决策。
- HEALTHCHECK --interval=30s --timeout=3s --retries=2 CMD curl -f http://localhost:8080/health || exit 1
- 返回 0 → 容器标记为 healthy;返回非 0 → 标记为 unhealthy,编排系统可据此提前下线流量
- 当容器因故障退出前已长期 unhealthy,运维系统可主动干预,而非等到 exit code 触发告警


















