2. Deployment滚动更新与回滚实战

Deployment滚动更新与回滚实战 学习卡片

Deployment 滚动更新与回滚实战

本案例使用一个可观测版本的 Web 应用镜像,通过 Deployment 的 strategy.rollingUpdate 控制替换节奏,触发一次镜像升级,观察 Pod 的替换过程,再用 kubectl rollout undo 回滚到上一版本并验证服务恢复。

1. 准备 Deployment 与滚动更新策略

先创建一个 4 副本的 Deployment,镜像使用 nginx:1.24-alpine,并显式声明滚动更新参数:maxSurge: 1 表示更新期间最多超出期望副本数 1 个 Pod,maxUnavailable: 0 表示更新期间不允许出现不可用 Pod,从而保证服务容量不下降。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-demo
spec:
  replicas: 4
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  selector:
    matchLabels:
      app: web-demo
  template:
    metadata:
      labels:
        app: web-demo
    spec:
      containers:
      - name: web
        image: nginx:1.24-alpine
        ports:
        - containerPort: 80
        readinessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 2
          periodSeconds: 3

应用并确认初始状态:

kubectl apply -f web-demo.yaml
kubectl get deploy web-demo
kubectl get pods -l app=web-demo -o wide

此时应看到 4 个 Running 且 Ready 的 Pod,Deployment 的 READY 为 4/4,UP-TO-DATE 为 4。

2. 滚动更新过程与参数关系

滚动更新的核心是 ReplicaSet 的扩缩容接力:新版本 ReplicaSet 逐步扩容,旧版本 ReplicaSet 逐步缩容,受 maxSurge 与 maxUnavailable 约束。下图展示 4 副本、maxSurge=1、maxUnavailable=0 时的替换节奏与 Pod 数量变化。

滚动更新:maxSurge=1,maxUnavailable=0,replicas=4 t0 初始 t1 新RS扩容 t2 旧RS缩容 t3 交替推进 t4 完成 旧 RS v1 Pod v1 ×4 可用 4 新 RS 0 总 Pod = 4 新 RS v2 Pod v2 ×1 旧 RS 4 新 RS 1 总 Pod = 5 (surge) 旧 RS 缩容 Pod v1 ×3 旧 RS 3 新 RS 1 总 Pod = 4 交替推进 v1×1 / v2×3 旧 RS 1 新 RS 3 总 Pod = 4 新 RS v2 Pod v2 ×4 旧 RS 0 新 RS 4 总 Pod = 4 约束关系 maxSurge=1 → 总 Pod 数最多 5(4+1),保证新 Pod 先就绪再缩旧 Pod maxUnavailable=0 → 可用 Pod 数始终 ≥ 4,服务容量不下降 回滚路径 kubectl rollout undo deployment/web-demo → 新 RS 缩容至 0,旧 RS 扩容回 4,Pod 镜像恢复为 nginx:1.24-alpine

3. 触发镜像版本更新

将镜像从 nginx:1.24-alpine 更新为 nginx:1.25-alpine,触发一次滚动更新:

kubectl set image deployment/web-demo web=nginx:1.25-alpine
kubectl rollout status deployment/web-demo

在另一个终端持续观察 Pod 替换过程:

kubectl get pods -l app=web-demo -w

预期现象:新 Pod 先创建并进入 Running/Ready,随后旧 Pod 被终止;由于 maxUnavailable=0,任意时刻 Ready 的 Pod 数不会低于 4。更新完成后,kubectl get deploy web-demo 的 UP-TO-DATE 与 AVAILABLE 均为 4。

4. 查看版本历史与回滚

查看 ReplicaSet 与 rollout 历史,确认新旧版本共存关系:

kubectl get rs -l app=web-demo
kubectl rollout history deployment/web-demo

执行回滚到上一版本:

kubectl rollout undo deployment/web-demo
kubectl rollout status deployment/web-demo

回滚后再次检查 Pod 镜像与 ReplicaSet 状态:

kubectl get pods -l app=web-demo -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[0].image}{"\n"}{end}'
kubectl get rs -l app=web-demo

预期结果:所有 Pod 的镜像恢复为 nginx:1.24-alpine,旧 ReplicaSet 重新扩容到 4,新 ReplicaSet 缩容到 0,Deployment 的 READY 回到 4/4。

5. 验证服务恢复

由于本例尚未创建 Service,可通过临时端口转发验证应用可访问:

kubectl port-forward deployment/web-demo 8080:80
curl -I http://127.0.0.1:8080/

预期返回 HTTP/1.1 200 OK,说明回滚后的 Pod 已正常提供 HTTP 服务。若返回 502/503,应检查 Pod 是否 Ready、readinessProbe 是否通过、镜像是否拉取成功。

回滚依赖 ReplicaSet 历史。默认 revisionHistoryLimit 为 10,若历史被清理或使用 kubectl apply 覆盖式更新导致模板未变化,可能无法回滚到预期版本。生产环境建议保留足够历史并记录每次变更的镜像 tag。
maxUnavailable=0 会要求集群有额外资源容纳 surge Pod;若节点资源不足,新 Pod 可能一直 Pending,滚动更新卡住。此时可适当调大 maxUnavailable 或先扩容节点。