docker stop 实现无损滚动更新需应用、容器与LB协同:先摘流再停机。核心是应用响应SIGTERM时关闭监听、等待请求完成并切换/readyz状态为503,LB通过短间隔健康检查(≤3秒)快速剔除节点,最后执行docker stop -t 30确保优雅终止。

使用 docker stop 配合负载均衡实现无损滚动更新,核心在于让容器在真正停止前,先从流量池中优雅摘除,避免新请求被路由到即将关闭的实例。这需要应用层、容器运行时和反向代理三者协同,而非仅靠 docker stop 自身。
理解 docker stop 的默认行为
docker stop 默认发送 SIGTERM 信号给容器主进程,等待 10 秒(可设 --time)后若未退出则发 SIGKILL 强制终止。但该操作本身不通知上游负载均衡器——如果 LB 仍把请求转发过来,就会导致 502/连接拒绝等错误。
要实现“无损”,必须在发 SIGTERM 前或同时,让 LB 主动剔除该节点。常见做法有:
- LB 支持健康检查(如 Nginx 的
health_check、Traefik 的 readiness probe),应用需提供/healthz或类似端点,并在收到终止信号后主动返回非健康状态 - 通过 API 动态下线节点(如 Consul、Nacos 注册中心 + LB 插件)
- 使用支持服务发现与生命周期钩子的编排工具(如 Docker Swarm 的
update-parallelism+update-delay,或 Kubernetes 的 preStop hook)
关键:应用需支持优雅退出与就绪探针
容器内应用必须能响应 SIGTERM 并执行以下动作:
- 停止接收新连接(如关闭 HTTP server 的监听 socket)
- 等待正在处理的请求完成(设置合理的超时,如 30 秒)
- 同步更新健康检查接口返回值(例如将
/readyz从200变为503,触发 LB 快速摘流)
示例(Node.js):
在收到 process.on('SIGTERM', ...) 后,立即调用 server.close(),并在回调中退出;同时让 /readyz 路由在关闭过程中返回 503。
负载均衡侧需配合快速感知与摘流
LB 的健康检查间隔和失败阈值直接影响“无损”效果。建议配置:
- 健康检查间隔 ≤ 3 秒,连续失败次数设为 1~2 次
- 避免使用长连接保活导致旧连接持续转发(如 Nginx 的
keepalive_timeout应短于应用优雅停机超时) - 若用 DNS 负载均衡(如 CoreDNS + SRV),需确保客户端支持 TTL 刷新并及时重解析
以 Nginx 为例,可结合 upstream 的 max_fails=1 fail_timeout=3s 和应用提供的 /readyz 接口做被动健康检查。
滚动更新流程示意(手动或脚本化)
不依赖 Swarm/K8s 时,可按如下顺序控制单节点更新:
- 调用 LB API 或修改配置,将目标容器 IP/端口从 upstream 中临时移除(或标记为 down)
- 等待 1~2 个健康检查周期,确认 LB 不再转发新请求
- 执行
docker stop -t 30 container_name,给应用留出处理存量请求的时间 - 启动新容器,待其
/readyz返回 200 后,再将其加回 LB upstream
整个过程需幂等、可重试,建议封装为带状态检查的 shell 或 Python 脚本,避免人工误操作。

















