tags: [Kubernetes, K8s系列, DevOps, 滚动更新, 回滚, 零停机, Deployment, 发布策略]
K8s 系列 | 第 27 天:滚动更新与回滚策略:实现零停机发布
第 27/30 天
引言
在生产环境中,应用更新是日常操作中最频繁也最危险的操作之一。如何在不中断用户访问的情况下完成版本升级?如何在更新出现问题时快速恢复到稳定版本?Kubernetes 的滚动更新(Rolling Update)与回滚(Rollback)机制正是为此而生。
今天我们将深入解析 K8s 的滚动更新策略、回滚机制以及生产环境中的最佳实践,帮助你在零停机的前提下安全、高效地管理应用版本。
一、核心概念
1.1 什么是滚动更新?
滚动更新是一种渐进式的应用部署策略,它通过逐步替换旧版本的 Pod 实例来更新应用,在整个过程中始终保持一定数量的 Pod 可用,从而实现零停机发布。
Kubernetes 的 Deployment 控制器原生支持滚动更新,无需额外工具或插件。其核心机制是创建一个新的 ReplicaSet,逐步扩容新 ReplicaSet 的同时缩容旧 ReplicaSet,直到所有 Pod 都更新到新版本。
1.2 滚动更新 vs 其他部署策略
| 策略 | 描述 | 适用场景 |
|---|---|---|
| 滚动更新 | 逐步替换 Pod | 绝大多数 Web 应用 |
| 蓝绿部署 | 同时运行两套环境,一次性切换 | 对稳定性要求极高的场景 |
| 金丝雀发布 | 先让少量用户使用新版本,验证后再全量 | 需要灰度验证的发布 |
| 重建(Recreate) | 先删除所有旧 Pod,再创建新 Pod | 开发环境或非关键应用 |
1.3 回滚机制
Kubernetes 的 Deployment 会保留历史版本(ReplicaSet 记录),你可以随时回滚到任意之前的版本。回滚本质上是反方向的滚动更新:将当前版本逐步替换为目标版本。
二、实战步骤
2.1 创建一个 Deployment 并设置滚动更新策略
首先,我们创建一个 Nginx Deployment,并配置滚动更新参数:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
labels:
app: my-app
spec:
replicas: 5
selector:
matchLabels:
app: my-app
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 15
periodSeconds: 20
关键参数说明:
maxSurge:更新过程中最多可以超过期望副本数的 Pod 数量。可以是绝对数(如1)或百分比(如25%)。值越大,更新速度越快,但资源消耗也越⼤。maxUnavailable:更新过程中最多可以有多少个 Pod 不可用。同样可以是绝对数或百分比。readinessProbe(就绪探针):新 Pod 只有在就绪探针通过后才开始接收流量,这是滚动更新安全性的核心保障。
2.2 触发滚动更新
更新镜像版本即可触发滚动更新:
# 方式一:直接更新镜像
kubectl set image deployment/my-app nginx=nginx:1.26
# 方式二:编辑 Deployment 配置
kubectl edit deployment my-app
# 方式三:应用新的 YAML 文件
kubectl apply -f deployment-v2.yaml
2.3 监控滚动更新过程
滚动更新过程中,你可以通过以下命令实时观察进度:
# 查看更新状态
kubectl rollout status deployment/my-app
# 输出示例:
# Waiting for rollout to finish: 2 out of 5 new replicas have been updated...
# deployment "my-app" successfully rolled out
# 查看 Deployment 的详细状态
kubectl describe deployment my-app
# 查看 ReplicaSet 的变化
kubectl get replicaset -l app=my-app
# 查看 Pod 的滚动更新过程
kubectl get pods -l app=my-app -w
2.4 暂停和恢复滚动更新
在某些场景下,你可能需要暂停更新以进行验证:
# 暂停滚动更新
kubectl rollout pause deployment/my-app
# 此时可以检查新 Pod 的运行状态
kubectl get pods -l app=my-app
# 确认无误后恢复更新
kubectl rollout resume deployment/my-app
2.5 回滚到上一个版本
当更新出现问题时,快速回滚是救命稻草:
# 回滚到上一个版本
kubectl rollout undo deployment/my-app
# 回滚到指定版本
kubectl rollout undo deployment/my-app --to-revision=2
# 查看历史版本记录
kubectl rollout history deployment/my-app
# 输出示例:
# deployment.apps/my-app
# REVISION CHANGE-CAUSE
# 1 <none>
# 2 kubectl set image deployment/my-app nginx=nginx:1.26
# 3 kubectl set image deployment/my-app nginx=nginx:1.27
# 查看特定版本的详细信息
kubectl rollout history deployment/my-app --revision=2
2.6 使用注解记录变更原因
为了让回滚时更清楚每个版本的目的,建议在更新时添加注解:
# 更新镜像并记录变更原因
kubectl set image deployment/my-app nginx=nginx:1.26
--record
# 或在 YAML 中通过 kubernetes.io/change-cause 注解记录
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
annotations:
kubernetes.io/change-cause: "升级 Nginx 到 1.26 版本,修复安全漏洞 CVE-2024-XXXX"
spec:
...
三、滚动更新策略调优
3.1 不同场景的策略配置
# 快速更新(适合开发环境)—— 允许大部分 Pod 同时不可用
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 3
maxUnavailable: 2
# 保守更新(适合生产环境)—— 确保大多数 Pod 可用
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
# 金丝雀式更新 —— 先更新一个 Pod 做验证
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
# 配合暂停:先等这个 Pod 验证通过,再恢复更新
3.2 健康检查的重要性
滚动更新的安全性高度依赖健康检查配置。如果缺少就绪探针,新 Pod 可能还未就绪就被加入 Service 的端点列表,导致请求失败:
# 推荐的生产环境就绪探针配置
readinessProbe:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: X-Health-Check
value: "true"
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
successThreshold: 1
failureThreshold: 3
3.3 Pod 中断预算(PDB)
对于有状态应用或关键服务,可以设置 PodDisruptionBudget 来限制同时中断的 Pod 数量:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: my-app-pdb
spec:
minAvailable: 3
selector:
matchLabels:
app: my-app
四、常见问题
4.1 滚动更新卡住怎么办?
滚动更新可能因为以下原因卡住:
– 新 Pod 就绪探针失败
– 资源配额不足
– 镜像拉取失败
# 诊断方法
kubectl describe deployment my-app # 查看 Events 部分
kubectl get pods -l app=my-app # 查看 Pod 状态
kubectl logs <new-pod-name> # 查看新 Pod 日志
# 常见修复
kubectl rollout resume deployment/my-app # 如果被暂停了
kubectl rollout undo deployment/my-app # 回滚到上一版本
4.2 回滚后历史版本被清除了?
Kubernetes 默认保留最近 10 个 ReplicaSet 历史版本。如果需要保留更多版本:
spec:
revisionHistoryLimit: 20
4.3 如何实现蓝绿部署?
虽然 K8s 原生不支持蓝绿部署,但可以通过 Service 的标签选择器实现:
# 第一步:部署蓝色环境(当前版本)
kubectl apply -f deployment-blue.yaml
# 第二步:部署绿色环境(新版本,服务标签不同)
kubectl apply -f deployment-green.yaml
# 第三步:切换 Service 指向绿色环境
kubectl patch service my-app -p '{"spec":{"selector":{"version":"green"}}}'
# 如需回滚,只需再次切换选择器
kubectl patch service my-app -p '{"spec":{"selector":{"version":"blue"}}}'
4.4 滚动更新与 ConfigMap/Secret 的热更新
Deployment 的滚动更新机制不会自动检测 ConfigMap 或 Secret 的变化。更新 ConfigMap 后,需要手动触发滚动更新:
# 方式一:使用 kubectl rollout restart 触发滚动更新
kubectl rollout restart deployment/my-app
# 方式二:修改 Deployment 的注解来触发更新
kubectl patch deployment my-app -p
'{"spec":{"template":{"metadata":{"annotations":{"updated-at":"'$(date +%s)'"}}}}}'
五、生产最佳实践
5.1 发布检查清单
- 预检查:确认资源配额充足、镜像存在且标签正确
- 健康检查:确保 readinessProbe 和 livenessProbe 配置正确
- 监控告警:发布前配置好相关监控指标和告警规则
- 备份准备:记录当前版本号,确保可以快速回滚
- 灰度验证:先在小部分流量上验证新版本
- 分步发布:按 10% → 30% → 100% 的节奏逐步推进
5.2 自动化发布流水线
结合 CI/CD 工具实现自动化滚动更新:
# GitLab CI / GitHub Actions 中的部署步骤示例
deploy:
stage: deploy
script:
# 更新镜像
- kubectl set image deployment/my-app
app=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
# 监控更新进度,超时自动回滚
- kubectl rollout status deployment/my-app
--timeout=5m || kubectl rollout undo deployment/my-app
5.3 回滚自动化策略
在 CI/CD 流水线中,可以设置自动化回滚条件:
#!/bin/bash
# 自动回滚脚本示例
# 执行滚动更新
kubectl set image deployment/my-app "app=$NEW_IMAGE"
# 监控更新,超时则自动回滚
if ! kubectl rollout status deployment/my-app --timeout=300s; then
echo "❌ 滚动更新超时,执行自动回滚..."
kubectl rollout undo deployment/my-app
kubectl rollout status deployment/my-app --timeout=300s
echo "✅ 已回滚到上一个版本"
exit 1
fi
# 验证应用健康状态
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" https://my-app.example.com/healthz)
if [ "$HTTP_CODE" != "200" ]; then
echo "❌ 健康检查失败,执行自动回滚..."
kubectl rollout undo deployment/my-app
exit 1
fi
echo "✅ 发布成功!"
总结
滚动更新是 Kubernetes 中最核心的发布策略,它通过渐进式替换 Pod 实现了零停机发布。今天我们学习了:
- 滚动更新的核心机制:通过新旧 ReplicaSet 的此消彼长实现平滑过渡
- 策略参数调优:
maxSurge和maxUnavailable控制更新速度和可用性 - 回滚机制:
kubectl rollout undo让你能快速回到安全版本 - 生产最佳实践:健康检查、PDB、自动化流水线、自动回滚
记住:没有健康检查的滚动更新不是滚动更新,而是盲目的替换。 在生产环境中,务必配置完善的就绪探针和存活探针,这才是零停机的真正保障。
📖 系列目录
- 第 1 天:Kubernetes 是什么?核心概念与架构全景解析
- 第 2 天:手把手搭建你的第一个 K8s 集群(kubeadm 实战)
- 第 3 天:Pod 详解:K8s 最小的调度单元与生命周期管理
- 第 4 天:Deployment 与 ReplicaSet:声明式应用管理
- 第 5 天:Service 与网络基础:ClusterIP、NodePort、LoadBalancer 详解
- 第 6 天:Namespace 与资源配额:多租户隔离基础
- 第 7 天:ConfigMap 与 Secret:配置管理最佳实践
- 第 8 天:Volume 与 PersistentVolume:存储抽象层的核心机制
- 第 9 天:StorageClass 与动态存储供给实战
- 第 10 天:StatefulSet:有状态应用的部署与管理
- 第 11 天:Ingress 与 Ingress Controller:外部流量接入全攻略
- 第 12 天:NetworkPolicy:K8s 网络安全策略与微隔离
- 第 13 天:Headless Service 与服务发现机制深度解析
- 第 14 天:CSI 存储插件与生产存储选型指南
- 第 15 天:污点与容忍度:掌控 Pod 调度
- 第 16 天:Node Affinity 与 Pod Affinity:精细化调度策略实战
- 第 17 天:HPA 水平自动扩缩:基于 CPU/内存/自定义指标的弹性伸缩
- 第 18 天:VPA 与 Cluster Autoscaler:资源与集群层的自动扩缩
- 第 19 天:Job 与 CronJob:批处理与定时任务实战
- 第 20 天:PriorityClass 与抢占式调度机制
- 第 21 天:资源配额与 LimitRange:多租户资源管控
- 第 22 天:监控体系搭建:Prometheus + Grafana + Kube-state-metrics
- 第 23 天:日志收集实战:EFK/ELK 栈在 K8s 中部署
- 第 24 天:RBAC 权限控制:ServiceAccount、Role、ClusterRole 深度解析
- 第 25 天:Helm Charts:包管理器使用与 Chart 开发实战
- 第 26 天:集群备份与恢复:etcd 快照 + Velero 方案
- 第 27 天:滚动更新与回滚策略:实现零停机发布 ← 本篇
- 第 28 天:集群升级最佳实践:Control Plane 与 Node 升级步骤 🔜
- 第 29 天:多集群管理:Federation / Cluster API / 多集群服务网格 🔜
- 第 30 天:K8s 生产环境踩坑实录:性能调优、故障排查与最佳实践 🔜
下期预告: 第 28 天我们将深入探讨 K8s 集群升级最佳实践,涵盖 Control Plane 组件升级、Node 节点升级、版本兼容性矩阵以及升级过程中的风险控制与回退方案。















暂无评论内容