停止慢的两个方向
docker stop 的动作是:给容器主进程发 SIGTERM,等待宽限期(默认 10 秒),仍未退出就发 SIGKILL 强杀。停得慢只有两类原因——应用根本没有处理信号,或者处理了但收尾本身耗时(长事务、批量落盘、向注册中心注销)。走到强杀这一步会跳过收尾逻辑,表现为日志最后几行缺失、退出码 137、数据可能不完整。加大宽限期只是给慢收尾留时间,治本仍在应用侧。
基本信息
| 默认行为 | SIGTERM 后等待 10 秒,再发 SIGKILL |
|---|---|
| 调整方式 | docker stop -t 30;compose 用 stop_grace_period |
| 量化工具 | time docker stop 容器,实测耗时 |
| 判断依据 | 退出码 143 表示自行响应,137 表示被强杀 |
典型使用场景
- 发布窗口评估:停机耗时直接决定滚动更新的总时长
- 数据完整性核查:强杀后检查缓冲数据是否落盘
- 配置优化:按实测收尾耗时设置合理的宽限期
- 应用改造验收:确认进程确实收到了信号并执行了清理
- 批量停机排期:多个实例串行停止,总量要提前估算
测量与调整
测量与调整
# 实测停机耗时
time docker stop web
# 给收尾慢的服务更长宽限期
docker stop -t 30 db
# 检查容器里是不是只有一个主进程在收信号
docker exec web sh -c 'ps -o pid,ppid,comm 2>/dev/null | head -10'
# 确认退出码:143 表示响应了信号,137 表示被强杀
docker inspect -f 'exit={{.State.ExitCode}}' db停机时间轴
| 阶段 | 发生的事 | 观察点 |
|---|---|---|
| 0 秒 | 发送 SIGTERM | 应用日志出现收到信号的记录 |
| 宽限期内 | 应用执行收尾 | 连接数下降、缓冲写盘完成 |
| 宽限期满 | 发送 SIGKILL 强杀 | 日志可能被截断,收尾逻辑被跳过 |
| 容器退出 | 确定退出码 | 143 属于响应后退出,137 属于被强杀 |
如果容器里主进程是个 shell 包装脚本,信号可能没有转发给真正的业务进程,需要确认 PID 1 的行为是否符合预期。
编排平台下线实例时通常会给一个不短于默认值的等待时间,实际生效值以编排配置为准,容器配置只是其中一层。