docker容器优雅上下线的核心是应用行为、容器配置与编排策略协同:启动时通过健康检查和readiness端点确保业务就绪再接入流量,停止时由pid 1进程捕获sigterm信号,在stop-grace-period或terminationgraceperiodseconds窗口内完成拒绝新请求、处理进行中请求、注销服务发现及资源清理等动作,并配合--init、prestop钩子等机制保障信号传递与执行可靠性。

让 Docker 容器优雅上下线,核心是“上得稳、下得准”:启动时服务就绪再对外提供流量,停止时等任务收尾再退出。这不单是命令调用问题,而是应用行为、容器配置、编排策略三者协同的结果。
启动阶段:确保服务真正就绪
容器启动后立即被加入负载均衡,但应用可能还在初始化数据库连接、加载缓存或预热 JVM——此时转发请求会失败。不能只看进程 running,要看业务 ready。
- 用健康检查(HEALTHCHECK)定义真实就绪状态,例如 HTTP GET /health 返回 200 才算通过
- 在 docker-compose.yml 或 Kubernetes 中配置 start_period 和 retries,避免因短暂探针失败误判
- 应用自身暴露 readiness 端点,并在所有依赖(DB、Redis、下游服务)连通、本地缓存加载完成后再返回 success
停止阶段:响应 SIGTERM 并完成清理
Docker 发送 SIGTERM 后,默认等待 10 秒;超时未退出则发 SIGKILL 强制终止。关键不是延长等待时间,而是让应用在这段时间里做对事。
- 确保 PID 1 是你的应用进程(而非 sh -c),否则信号无法送达 —— CMD ["node", "app.js"] 正确,CMD ["sh", "-c", "node app.js"] 错误
- 代码中监听 SIGTERM(Go 用 signal.Notify,Java 用 Runtime.addShutdownHook,Spring Boot 2.3+ 开箱支持 graceful shutdown)
- 收到信号后:拒绝新请求、等待 in-flight 请求完成、注销服务发现、关闭连接池、刷写缓冲数据、释放文件句柄
编排层配合:给足时间,传对信号
单机 docker run 要设 stop_grace_period,Kubernetes 更需关注 terminationGracePeriodSeconds 和 preStop 生命周期钩子。
- docker-compose.yml 中设置:stop_grace_period: 30s,覆盖默认 10 秒
- Kubernetes Pod 中配置:terminationGracePeriodSeconds: 45,并搭配 preStop 执行平滑摘流量(如 sleep 5; curl -X POST http://localhost:8080/quitquitquit)
- 使用 --init 启动容器(如 docker run --init ...),借助 tini 避免僵尸进程,提升信号转发可靠性
验证是否真优雅:别只看 exit code
容器退出码为 0 不代表优雅,可能是 SIGKILL 强杀后内核返回的默认值。要靠日志和外部观测确认行为。
- 日志中应明确出现 “Received SIGTERM”、“Shutting down server…”、“All requests drained” 等关键词
- 监控指标观察:活跃连接数应归零、in-flight 请求计数平稳下降至 0、无连接 reset 或 timeout 上升
- 测试方法:docker stop 同时发起持续请求,验证最后一批响应是否全部成功返回,而非 502/503











