《运维必备:零停机实现服务滚动更新的五种工具与实战指南》
目录导读
- 为什么需要滚动更新?
- Kubernetes原生Deployments滚动更新
- Docker Swarm服务滚动升级
- Ansible结合负载均衡的零停机更新
- Nomad的任务组滚动策略
- 自定义脚本+反向代理(Nginx/HAProxy)
- 常见问题QA
为什么需要滚动更新?
问:滚动更新与传统“全部停止再启动”相比,优势在哪?
答:滚动更新能逐个替换服务实例,使应用在更新期间始终对外可用,避免停机导致的业务中断、用户流失和收入损失,根据Google SRE报告,采用滚动更新的系统可用性可达99.99%以上。

关键实现原理:保持最小健康实例数(如 maxSurge 和 maxUnavailable 参数),逐步用新版本替换旧版本,同时通过健康检查(liveness/readiness probe)确保新实例就绪后才下线旧实例。
Kubernetes原生Deployments滚动更新
Kubernetes(简称K8s)的Deployment资源内置滚动更新策略,是云原生场景下最常用的工具。
核心配置(YAML示例)
apiVersion: apps/v1
kind: Deployment
spec:
replicas: 5
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 // 允许额外创建1个新Pod
maxUnavailable: 1 // 允许1个旧Pod不可用
template:
spec:
containers:
- name: app
image: myapp:v2
readinessProbe:
httpGet:
path: /healthz
initialDelaySeconds: 5
periodSeconds: 10
执行命令
kubectl set image deployment/myapp myapp=myapp:v2 --record kubectl rollout status deployment/myapp # 监控状态 kubectl rollout undo deployment/myapp # 回滚
实战技巧:
- 设置
progressDeadlineSeconds(默认600秒)避免更新卡死 - 结合HPA(水平自动扩缩容),滚动更平滑
Docker Swarm服务滚动升级
Docker Swarm适合中小团队,配置简单。
更新命令
docker service update --image myapp:v2 --update-parallelism 2 --update-delay 10s my_service
--update-parallelism:同时更新的副本数--update-delay:每批更新后的等待时间(用于健康检查)
问:Swarm如何确保新服务正常工作?
答:通过 --update-failure-action pause(默认),一旦新副本健康检查失败,自动暂停更新并保持旧版本运行。
Ansible结合负载均衡的零停机更新
适用于传统虚拟机或裸机环境,通过编排工具控制更新节奏。
Playbook关键片段
- name: 滚动更新Web服务
hosts: web_servers
serial: 1 # 每次只更新1台主机
tasks:
- name: 从负载均衡器移除
haproxy:
state: disabled
host: "{{ ansible_host }}"
backend: myapp_backend
delegate_to: lb01
- name: 更新应用
docker_container:
image: myapp:v2
name: myapp
state: started
restart: true
- name: 健康检查
uri:
url: "http://{{ ansible_host }}:8080/health"
register: result
until: result.status == 200
retries: 10
- name: 加入负载均衡器
haproxy:
state: enabled
host: "{{ ansible_host }}"
backend: myapp_backend
delegate_to: lb01
优势:支持任意负载均衡器(Nginx/HAProxy/云厂商LB),完全自定义更新逻辑。
Nomad的任务组滚动策略
HashiCorp Nomad适合混合云编排,使用 update 块定义滚动参数。
Job规范示例
job "web" {
group "app" {
count = 5
update {
max_parallel = 1
min_healthy_time = "10s"
healthy_deadline = "5m"
progress_deadline = "10m"
auto_revert = true
}
}
}
问:Nomad的“自动回滚”如何工作?
答:如果新版本部署失败(健康检查持续不通过),Nomad会自动将任务组回退到上一个稳定版本,无需人工干预。
自定义脚本+反向代理(Nginx/HAProxy)
适合极端定制化需求的场景,例如老旧系统或特殊网络环境。
Bash脚本核心逻辑
#!/bin/bash
SERVERS=("192.168.1.10" "192.168.1.11" "192.168.1.12")
for server in "${SERVERS[@]}"; do
# 1. 从Nginx upstream移除
ssh lb "sed -i 's/server ${server}:8080;/server ${server}:8080 down;/' /etc/nginx/upstream.conf"
ssh lb "nginx -s reload"
# 2. 更新目标服务器
ssh "$server" "docker pull myapp:v2 && docker-compose up -d web"
# 3. 健康检查
while ! curl -s "http://${server}:8080/health" | grep "ok"; do
sleep 2
done
# 4. 重新加入负载均衡
ssh lb "sed -i 's/server ${server}:8080 down;/server ${server}:8080;/' /etc/nginx/upstream.conf"
ssh lb "nginx -s reload"
done
注意:需配合 nginx -s reload 的热重载特性,避免重启导致连接中断。
常见问题QA
Q1:滚动更新时如何处理数据库Schema变更?
A:遵循“向后兼容”原则,先执行数据库迁移(允许旧版本代码读取新字段),再滚动更新应用代码,推荐使用Flyway或Liquibase管理迁移。
Q2:如果新版本有严重Bug,如何快速回滚?
A:
- K8s:
kubectl rollout undo - Swarm:
docker service update --rollback - Nomad:设置
auto_revert = true自动回滚 - 自定义:保留旧镜像标签,重新执行更新脚本的反向顺序
Q3:滚动更新过程中,部分旧实例仍在运行,如何保证请求路由到正确版本?
A:
- 使用服务网格(Istio/Linkerd)的流量镜像或金丝雀发布。
- 或在反向代理层根据Cookie/Header将部分流量导向新版(金丝雀策略)。
Q4:滚动更新性能优化建议?
A:
- 减少
maxUnavailable值(如设为0)避免容量骤降 - 缩短健康检查间隔(但避免频繁检查影响性能)
- 利用
preStop钩子优雅关闭旧实例(等待已接收请求完成)
选择工具需根据团队规模与环境类型——K8s适合大规模容器化,Swarm简单易用,Ansible适合传统架构,Nomad适合多云混合,自定义脚本适合高度定制,核心原则始终是:保障健康检查、控制更新速度、保留回滚能力。
标签: 滚动更新