Docker stop 默认发送 SIGTERM 信号,因其支持优雅终止并预留10秒等待期,超时才发SIGKILL;业务需正确处理该信号,确保主进程为PID 1、显式监听、避免后台化、设合理stop_timeout并验证。

Docker stop 默认发送 SIGTERM 信号给容器主进程,这是合理且符合 POSIX 习惯的做法,但能否真正安全退出,取决于你的业务进程是否正确处理该信号。
为什么默认用 SIGTERM 而不是 SIGKILL
SIGTERM 是“礼貌性终止”信号,允许进程主动释放资源、保存状态、关闭连接、完成正在处理的任务。Docker 给出 10 秒等待窗口(可通过 -t 参数调整),超时后才发 SIGKILL 强制结束。直接用 SIGKILL 会跳过所有清理逻辑,容易导致数据丢失、连接中断、临时文件残留或数据库不一致。
常见业务不兼容 SIGTERM 的表现
- 进程忽略 SIGTERM(未注册信号处理器,或仅捕获了 SIGINT)
- 主进程是 shell 脚本启动的多进程服务,SIGTERM 只杀掉了 shell,子进程变成孤儿继续运行
- Java 应用未配置 shutdown hook,或 hook 中阻塞/耗时过长
- Node.js 应用监听了 SIGTERM,但异步任务(如未 await 的 Promise、定时器、未关闭的 HTTP server)未等待完成就退出
- Go 程序用 os.Exit() 提前退出,绕过了 defer 和 context.Cancel
让业务真正兼容 SIGTERM 的关键做法
- 主进程必须是 PID 1:避免 init 系统缺失导致信号无法传递;推荐使用 tini 或设置 init: true 在 docker run 中
- 显式监听 SIGTERM:在代码中注册处理器,并触发优雅关闭流程(如关闭 HTTP server、等待 worker 退出、提交 offset)
- 避免后台化/daemonize:容器内不要调用 nohup、& 或 setsid,否则主进程可能提前返回,失去对子进程控制
- 设置合理的 stop_timeout:根据业务最长清理时间调整,例如批量写入场景可设为 30s 或 60s
-
验证行为:用 docker stop -t 5
测试是否在 5 秒内干净退出;配合 docker logs 和应用日志确认 shutdown hook 是否执行
调试小技巧
若不确定进程是否收到 SIGTERM,可在容器内运行:
kill -l 查看信号编号(TERM 通常是 15)
trap 'echo "got SIGTERM"; exit 0' TERM 快速验证信号捕获
ps auxf 观察进程树结构,确认主进程是否真正管理子进程










