生产环境用 Docker Compose 实现零停机更新,核心是配置 healthcheck 健康检查 + deploy.update_config.order 设为 start-first,配合优雅关闭逻辑,适合单主机多副本场景;若需要更完整的滚动更新能力,建议结合 Docker Swarm 或迁移到 Kubernetes。
先说结论:Docker Compose 可以通过健康检查和更新顺序配置实现最小化中断更新,但原生滚动更新能力有限,生产环境需配合外部负载均衡或考虑 Swarm 模式。
- 适合:单主机多副本服务、有健康检查接口的应用、可优雅关闭的服务
- 先准备:配置 healthcheck、设置 stop_grace_period、确保应用监听 SIGTERM 信号
- 验收:更新过程中持续请求测试、检查容器状态、验证日志无错误
命令速用版
基础更新命令(后台执行,避免阻塞):
docker-compose up -d `--no-deps` <service_name>
带构建的更新(代码变更后):
docker-compose up -d `--build` `--no-deps` <service_name>
查看容器健康状态:
docker-compose ps
检查特定容器健康详情:
docker inspect `--format`='{{.State.Health.Status}}' <container_id>为什么会这样
Docker Compose 执行更新时,默认行为是先停止旧容器再启动新容器,这会导致短暂的服务中断。要实现零停机,关键在于改变这个顺序:让新容器先启动并通过健康检查,确认就绪后再停止旧容器。
这个过程依赖三个条件:第一,应用需要提供健康检查接口(如/healthz),让 Compose 能判断容器是否真正就绪;第二,应用需要支持优雅关闭,收到 SIGTERM 信号后完成正在处理的请求再退出;第三,需要有多个副本或外部负载均衡,确保更新期间始终有可用实例处理流量。
需要注意的是,Docker Compose 本身的滚动更新能力不如 Kubernetes 或 Docker Swarm 完整,单副本服务即使配置了 start-first 也可能出现短暂不可用。
分步处理
第一步:配置健康检查
在 docker-compose.yml 中为服务添加 healthcheck,确保 Compose 能检测容器是否真正可用:
services:
web:
image: myapp:v2
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80/healthz"]
interval: 10s
timeout: 3s
retries: 3
start_period: 40s检查点:执行 docker-compose up 后,用 docker-compose ps 查看状态列应显示 (healthy)。
第二步:配置更新策略
使用 deploy 配置控制更新顺序和并行度(注意:deploy 在 Swarm 模式下才完全生效,普通 Compose 部分支持):
services:
web:
deploy:
replicas: 2
update_config:
parallelism: 1
delay: 10s
order: start-first关键点:order: start-first 确保新容器启动并健康后,旧容器才会被停止。
第三步:配置优雅关闭
设置 stop_grace_period 给容器足够时间完成正在处理的请求:
services:
web:
stop_grace_period: 30s同时确保应用代码监听 SIGTERM 信号,收到后完成当前请求再退出。以 Go 服务为例,需要捕获 syscall.SIGTERM 并调用 server.Shutdown()。
第四步:执行更新
更新镜像版本后执行:
docker-compose pull docker-compose up -d `--no-deps` web
回滚提醒:如果更新后发现问题,立即执行 docker-compose up -d `--no-deps` web 回退到上一版本镜像(需提前保留旧镜像)。
怎么验证是否生效
检查容器健康状态
docker-compose ps # 状态列应显示 (healthy) 而非 (starting) 或 (unhealthy)
持续请求测试
在另一个终端执行持续请求,观察更新过程中是否有失败:
while true; do curl -s http://localhost:80/healthz; echo; sleep 1; done
更新期间不应出现连接拒绝或 500 错误。
查看容器启动顺序
docker ps `--format` "table {{.Names}}\t{{.Status}}\t{{.CreatedAt}}"
# 确认新容器创建时间在旧容器停止之前检查应用日志
docker-compose logs `--tail`=100 web # 确认无异常错误,优雅关闭日志正常
常见坑
单副本服务的局限
即使配置了 start-first,单副本服务在新旧容器切换瞬间仍可能出现短暂不可用。生产环境建议至少 2 个副本,或配合外部负载均衡使用。
deploy 配置的兼容性
deploy 配置在 Docker Compose v3+ 中定义,但完整功能需要 Docker Swarm 模式。普通 docker-compose up 可能忽略部分 deploy 参数,需提前测试验证。
健康检查接口缺失
如果应用没有健康检查端点,healthcheck 配置无法生效。需要先在代码中实现/healthz 或类似接口,返回 200 状态码表示服务就绪。
数据库迁移风险
零停机更新只解决服务层连续性问题,数据库结构变更可能新旧版本不兼容。建议采用向后兼容的迁移策略,或单独安排数据库维护窗口。
资源不足导致启动失败
start-first 策略会同时运行新旧容器,需要确保主机有足够资源(CPU、内存)支撑临时加倍的容器数量,否则新容器可能启动失败导致更新中断。
参考来源
- CSDN 博客 - Docker Compose 服务如何实现零 downtime 更新?90% 工程师忽略的 3 个关键步骤
- CSDN 博客 - 【Docker Compose 平滑更新实战指南】:掌握零停机部署的 5 大核心技巧
- CSDN 博客 - 【资深架构师亲授】:如何用 docker-compose up `--build` 实现零停机发布?
- 阿里云开发者社区 - 零停机部署 Go 服务:用 Docker Compose + 滚动更新,上线如换轮胎不停车
- GitCode - 3 步实现零停机!Docker Compose 持续部署全流程解析