本节摘要:值班手册第二页——四个"往下带"的动词:stop(熄火)、restart(复航)、pause(冻结)、rm(送离)。本节讲清各自的精确语义、优雅停机的时间窗机制,以及"强拆成瘾"的代价。
起吊容易停船难。新手对停容器的全部理解是"执行 stop 就停了",但值班员的视角里至少有四个问题要回答:应用来得及保存数据吗?宽限期怎么算?暂停和停止差在哪?什么时候才允许强拆?本节逐一对答。
先看最核心的机制——优雅停机的时间窗。stop 命令并不是"掐断"容器,而是一个有礼貌的两段式动作:先向主进程发送温和的终止信号(SIGTERM),给应用留出收拾现场的时间(保存数据、关闭连接、写完日志);若宽限期内应用自己退了,皆大欢喜;若到点还不退,才发强制信号(SIGKILL)一锤定音。默认宽限十秒,可用参数调整:

stop:熄火。 进程收到温和信号、走完时间窗,容器进入 Stopped 状态——档案还在、可写层还在、随时可复航:
# 标准停船:默认十秒宽限 docker stop order-api # order-api # 数据库箱子:放宽到六十秒,给检查点刷盘留足时间 docker stop -t 60 order-db # 停船后容器仍在(假故障高发点):用 -a 确认 docker ps -a --filter name=order-api --format "{{.Names}}: {{.Status}}" # order-api: Exited (0) 20 seconds ago
restart:复航。 一个常用的复合动作:停(含宽限)再起。两种场景——配置或资源参数变更后重载(update 改不了的运行时项),以及应用偶发抽风时的"先重启再排查"应急:
# 重启并核验 docker restart order-api # order-api docker ps --filter name=order-api --format "{{.Status}}" # Up 3 seconds # 区分:docker start 只对已停止的容器有效;restart 对运行中的也有效
pause:冻结。 这是与 stop 有本质区别的动作——pause 不终结进程,只把它冻住:进程还在内存里、信号被扣住、CPU 时间片停发,解冻(unpause)后从冻结点继续跑,就像比赛暂停而不是比赛结束:
# 冻结与解冻 docker pause order-api docker ps --filter name=order-api --format "{{.Status}}" # Up 34 seconds (Paused) <- 状态标注 Paused docker unpause order-api # order-api
适用场景要拿捏:想临时释放 CPU 让位给紧急任务,pause 合适;要发布新版本或释放内存,必须 stop——冻结的进程仍占着全部内存。
rm:送离。 拆箱回收,可写层数据随之清除(上一章的结论)。运行中的箱子默认拒绝拆除,-f 是强拆通道:
# 规范送离:先停后删 docker stop order-api && docker rm order-api # 强拆:跳过宽限直接终结并拆除(强制信号,应用无收尾机会) docker rm -f order-api
rm -f 与 stop 缺席的部署脚本(直接 rm -f 上来就干)在开发机上是效率,在生产上是事故源。强拆的代价清单:写操作被腰斩(数据库与消息队列最敏感,可能触发恢复流程甚至数据损坏)、外部系统不知情(下游还以为箱子在服务,连接错误突然爆发)、监控与审计断片(最后的日志常被打断)。纪律很简单:生产停船必须走 stop 的宽限流程,强拆仅留给明确确认无状态或已下线的箱子。批量清理停止容器用现成命令,避免逐个 rm 的手工活:
# 一键清掉全部已停止的容器(先看清单再执行,防止误删还想复航的箱子) docker ps -a --filter status=exited --format "{{.Names}}: {{.Status}}" docker container prune # 确认后输出:Total reclaimed space: 1.24GB
宽限机制还有一个应用侧的配套开关值得知道:停止信号可以按镜像定制。有些老应用不认默认的温和信号,或者收尾动作特别长,装箱单里可以用 STOPSIGNAL 指定引擎停船时发的信号种类;更常见的做法是在应用里注册信号处理——收到温和信号时先把队列里的活干完再退出。这就解释了为什么"同一个 stop 命令,有的应用秒停、有的应用磨蹭到被强制":停得体不体面,一半责任在应用自己有没有学会"听信号"。验证一只箱子的收尾风度也很简单:
# 停船计时:观察应用是真优雅还是被强制的 time docker stop grace-test # real 0m0.4s <- 远小于宽限期:应用自己快速退场,优雅 # real 0m10.1s < 贴着宽限期上限:大概率是被强制收尾的,需要排查应用信号处理
停船之后还有一个必读信息——退出码,它是箱子离开时留下的字条,ps -a 的状态栏与 inspect 的档案里都能读到。值班员应当对它形成条件反射:
# 两条途径读退出码 docker ps -a --filter name=order-api --format "{{.Status}}" # Exited (143) 3 minutes ago docker inspect order-api --format "退出码:{{.State.ExitCode}} 被内核击杀:{{.State.OOMKilled}}" # 退出码:143 被内核击杀:false
三个高频码值得背下:0 是正常完成,一次性任务的箱子就该拿这个成绩退场;143 是收到温和信号后自行退出——优雅停机的理想落幕;137 是被强制信号终结(宽限期到点,或内存超配被内核击杀),生产环境见到它就该追问一句"为什么没收住尾"。退出码把 4.1 节的状态图落成了可记录、可告警的数字,第 7 章的排错章节还会回头用它定位事故。
箱子停得好,还要进得去。下一节:钻进箱子检修的两条路——exec 与 attach。