使用docker rollout搭配Traefik时如何避免服务停机?
解决Traefik + Docker Rollout零停机部署请求失败问题
核心原因
你的问题本质是Docker Rollout的默认停止流程未与Traefik的服务发现/健康检查机制联动:旧容器在未被Traefik从路由列表移除、未处理完现有请求的情况下就被终止,导致请求被丢弃。
具体解决方案
1. 给应用容器配置健康检查与优雅停止
Traefik只会将请求转发到标记为「健康」的容器,同时容器需要支持优雅终止现有请求:
- 在
docker-compose.yml或容器配置中添加健康检查,确保Traefik能实时感知容器状态:services: your-app: image: your-app:new-version # 容器健康检查(与Traefik的健康检查对应) healthcheck: test: ["CMD", "curl", "-f", "http://localhost/health"] # 替换为你的健康检查接口 interval: 5s timeout: 3s retries: 3 start_period: 10s # 容器启动后等待多久开始检查 # 优雅停止:收到停止信号后等待30秒处理完请求再退出(根据业务调整) stop_grace_period: 30s # 可选:指定停止信号(默认SIGTERM,多数应用已支持) stopsignal: SIGTERM
2. 配置Traefik的负载均衡规则,添加终止延迟与健康检查
让Traefik在容器下线时,先处理完现有请求再移除路由,同时只转发健康实例:
services: your-app: labels: # 基础Traefik配置 - traefik.enable=true - traefik.http.routers.your-app.rule=Host(`your-domain.com`) # Traefik健康检查(与容器健康检查联动) - traefik.http.services.your-app.loadbalancer.healthcheck.path=/health - traefik.http.services.your-app.loadbalancer.healthcheck.interval=5s - traefik.http.services.your-app.loadbalancer.healthcheck.timeout=3s # 终止延迟:容器下线后,Traefik继续保留该实例30秒,处理现有请求 - traefik.http.services.your-app.loadbalancer.termination_delay=30s
3. 调整Docker Rollout的部署策略,等待新容器就绪再处理旧容器
使用docker rollout的健康检查等待参数,确保新容器完全就绪(被Traefik识别并加入路由)后,再逐步停止旧容器:
# 执行滚更时,等待新容器健康状态正常后再继续 docker rollout update --wait --health-check your-app
--wait:等待新容器部署完成并健康--health-check:使用容器自身的健康检查作为就绪判断标准
4. 确保Traefik实时监听Docker事件
确认Traefik的Docker Provider已开启watch模式,能实时感知容器状态变化:
services: traefik: command: - "--providers.docker=true" - "--providers.docker.watch=true" # 必须开启,实时同步容器状态 - "--providers.docker.exposedbydefault=false"
验证方案
重新执行ab -n 1000 -c 3 http://your-domain.com/测试,此时:
- Docker Rollout启动新容器,等待其健康检查通过
- Traefik将新容器加入路由,开始转发请求
- Docker Rollout向旧容器发送SIGTERM信号,旧容器进入优雅停止阶段
- 旧容器的健康检查失败,Traefik停止向其发送新请求
- 旧容器在
stop_grace_period内处理完现有请求后退出 - Traefik在
termination_delay后彻底移除旧容器路由
内容的提问来源于stack exchange,提问作者eeeeeeeeeeeeeeeeeeeeeeeeeeeeee
相关产品推荐
相关产品推荐

