K8s 系列 | 第 27 天:滚动更新与回滚策略:实现零停机发布


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 发布检查清单

  1. 预检查:确认资源配额充足、镜像存在且标签正确
  2. 健康检查:确保 readinessProbe 和 livenessProbe 配置正确
  3. 监控告警:发布前配置好相关监控指标和告警规则
  4. 备份准备:记录当前版本号,确保可以快速回滚
  5. 灰度验证:先在小部分流量上验证新版本
  6. 分步发布:按 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 的此消彼长实现平滑过渡
  • 策略参数调优maxSurgemaxUnavailable 控制更新速度和可用性
  • 回滚机制kubectl rollout undo 让你能快速回到安全版本
  • 生产最佳实践:健康检查、PDB、自动化流水线、自动回滚

记住:没有健康检查的滚动更新不是滚动更新,而是盲目的替换。 在生产环境中,务必配置完善的就绪探针和存活探针,这才是零停机的真正保障。

📖 系列目录

下期预告: 第 28 天我们将深入探讨 K8s 集群升级最佳实践,涵盖 Control Plane 组件升级、Node 节点升级、版本兼容性矩阵以及升级过程中的风险控制与回退方案。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片快捷回复

    暂无评论内容