容器停止超时本质是sigterm发出后主进程未在规定时间内退出,关键在于未及时收尾;exited(137)表明被sigkill强杀,需检查日志是否响应信号、调整stop_timeout并确保主进程为pid 1且正确监听sigterm。

容器停止超时,本质是 SIGTERM 信号发出后,主进程没在规定时间内退出。关键不在“停不掉”,而在“没来得及收尾”——比如数据库刷盘卡住、长事务未提交、连接池 draining 慢、或应用根本没监听 SIGTERM。
确认是否真被强杀(看退出码)
执行 docker ps -a 查看目标容器状态:
- 显示 Exited (0):主进程收到 SIGTERM 并正常退出,大概率已优雅完成
- 显示 Exited (137):被 SIGKILL 强制终止,说明超时了(137 = 128 + 9,即 SIGKILL 的编号 9)
- 显示 Exited (1) 或其他非零非137码:可能是应用自身异常退出,需结合日志进一步判断
检查日志里有没有响应 SIGTERM
运行 docker logs <container> --tail 50</container>,重点找这些关键词:
- received SIGTERM、shutting down、gracefully stopping
- 是否有清理动作的输出,比如 “closing database connections”、“draining HTTP server”
- 若日志最后几行直接中断、无任何关闭提示,说明应用未捕获信号或主进程不是 PID 1(常见于 shell 封装启动)
调整停止宽限期(stop timeout)
默认 10 秒对多数服务偏短,尤其涉及 I/O 或网络等待的场景。调整方式如下:
-
临时手动停止时:用
docker stop --time=30 <name></name>设为 30 秒 -
运行时指定:启动容器时加
--stop-timeout=30,如docker run -d --stop-timeout=30 myapp -
Docker Compose 中:在 service 下配置
stop_grace_period: 30s
建议值参考:纯 Web 服务可设 15–20 秒;带数据库写入或批量任务的服务建议 30–60 秒;避免设超过 120 秒,否则拖慢 CI/CD 或滚动更新节奏。
确保应用能真正响应 SIGTERM
光调时间不够,还得让程序“听得见”:
- 主进程必须是 PID 1,否则收不到信号。避免用
sh -c "exec myapp"启动,改用exec myapp - 代码中显式监听
SIGTERM(Go/Python/Node.js 等主流语言均有标准做法) - 必要时加
--init参数启动容器,让 tini 作为 PID 1 转发信号并处理僵尸进程 - Dockerfile 中可声明
STOPSIGNAL SIGTERM,明确终止信号类型(虽默认就是 SIGTERM)











