Deployment 滚动更新与回滚:从原理到手操(上)

Deployment 滚动更新与回滚:从原理到手操(上)

我们每天都在 kubectl apply 更新镜像版本,然后等 Pod 一个个替换完。但你真的了解 apply 之后发生了什么吗?

  • Deployment 更新时,不是直接改 Pod,而是创建新 ReplicaSet(RS),逐步用新 RS 的 Pod 替换旧 RS 的 Pod
  • 旧 RS 不会立刻删除------它是你回滚的"安全绳"
  • maxSurgemaxUnavailable 两个参数,决定了更新过程有多激进还是多保守

上集聚焦 Deployment 的核心机制:三级结构、滚动更新策略调优、暂停恢复、以及回滚全流程。下集我们讲蓝绿部署、灰度发布和运维排坑。


一、Deployment 是什么?

Deployment 是 Kubernetes 中最常用的无状态应用 部署控制器。它提供声明式更新机制,你只需要告诉 K8s"我要 3 个 nginx:1.24.0",它自己去搞定------创建 RS、调度 Pod、监控健康状态、处理滚动更新和回滚。

1.核心功能一览

功能 说明
Pod 副本管理 确保指定数量的 Pod 副本持续运行
滚动更新 逐步替换旧 Pod,零停机发布
版本回滚 一键回退到任意历史版本(基于 RS 快照)
自动修复 节点故障时自动在新节点重建 Pod
扩缩容 手动 kubectl scale 或 HPA 自动扩缩
暂停/恢复 控制更新节奏,实现分批发布

2.Deployment vs StatefulSet vs DaemonSet

特性 Deployment StatefulSet DaemonSet
适用场景 无状态应用 (nginx, API) 有状态应用 (MySQL, Kafka) 节点级部署 (日志采集, 监控)
Pod 命名 随机 (nginx-7f6b5d4cf9-abc) 有序 (mysql-0, mysql-1) 随机
存储卷 共享或无需持久化 每个 Pod 专属 PVC 可选
滚动更新 支持 支持 支持

一句话选型:写 API 用 Deployment,跑数据库用 StatefulSet,每个节点跑 Agent 用 DaemonSet。

3.常用命令速查

bash 复制代码
# 创建
kubectl create deployment nginx --image=nginx:1.24.0 --replicas=3
kubectl apply -f deploy.yaml

# 查看
kubectl get deploy -o wide            # Deployment 概览
kubectl describe deployment nginx     # 详细状态和 Events
kubectl get rs -l app=nginx           # 关联的 ReplicaSet
kubectl get pods -o wide -l app=nginx # Pod 分布

# 扩缩
kubectl scale deployment nginx --replicas=5

# 更新
kubectl set image deployment/nginx nginx=nginx:1.26.0
kubectl rollout status deployment/nginx

# 回滚
kubectl rollout undo deployment/nginx
kubectl rollout undo deployment/nginx --to-revision=2

# 删除
kubectl delete deployment nginx

二、Deployment 三级结构:Deployment → RS → Pod

Deployment 并不直接管 Pod,它的管理链路是:

复制代码
Deployment → ReplicaSet → Pod

1.为什么不是 Deployment → Pod?

因为 RS 是版本管理的载体。每次 Deployment 更新镜像版本,都会创建一个新的 RS,而不是原地修改 Pod。旧 RS 保留(副本数缩为0),新 RS 逐步扩容。

验证这个结构:

bash 复制代码
# 创建 Deployment
kubectl create deployment nginx --image=nginx:1.22.1 --replicas=3

# 查看 RS------注意 RS 名称后缀是 Pod template 的 hash
kubectl get rs
# NAME               DESIRED   CURRENT   READY   AGE
# nginx-7f6b5d4cf9   3         3         3       30s

# 更新镜像版本
kubectl set image deployment/nginx nginx=nginx:latest

# 再看 RS------旧 RS副本数变0,新 RS出现
kubectl get rs
# NAME               DESIRED   CURRENT   READY   AGE
# nginx-7f6b5d4cf9   0         0         0       2m   ← 旧版,副本=0但不删
# nginx-5b8d7c6e2a   3         3         3       10s  ← 新版

# 查看 Pod
kubectl get pods --show-labels
# 注意 Pod 的 pod-template-hash label 不同,归属不同 RS

2.核心理解

  • 每个 RS 对应一个 Pod template 版本,名称后缀是 template hash
  • 滚动更新 = 新 RS 扩容 + 旧 RS 缩容,同时进行
  • 旧 RS 副本数变为0但不删除,回滚时直接扩容旧 RS 即可
  • revisionHistoryLimit(默认10)控制保留多少个旧 RS,超出才会清理

三、滚动更新策略:maxSurge / maxUnavailable 调优

1.Deployment 的更新策略

策略 行为 适用场景
RollingUpdate(默认) 逐步替换,新旧并存 大多数场景
Recreate 先杀所有旧 Pod,再建新 Pod 新旧版本不兼容(如数据库schema变更)

完整 YAML 示例:

yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 3
  revisionHistoryLimit: 10      # 保留10个历史版本(用于回滚)
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1               # 更新期间最多超出期望副本数的 Pod 数
      maxUnavailable: 0         # 更新期间最多允许不可用的 Pod 数
  #Pod Ready 后等30秒才认为真正可用
  #防止 Pod 刚 Ready 就被纳入可用计数(应用可能还在初始化缓存)    
  minReadySeconds: 30        
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.22.1
        imagePullPolicy: IfNotPresent
1.1 maxSurge:多建几个 Pod 过渡
  • 值可以是整数(如 1)或百分比(如 25%
  • 作用 :更新期间,集群中最多有 replicas + maxSurge 个 Pod
  • replicas=3, maxSurge=1 → 更新期间最多4个Pod(3旧+1新 或 2旧+2新)
1.2 maxUnavailable:容忍几个 Pod 不可用
  • 值可以是整数(如 1)或百分比(如 25%
  • 作用 :更新期间,最少有 replicas - maxUnavailable 个 Pod 可用
  • replicas=3, maxUnavailable=0 → 更新期间至少3个Pod可用(零中断)

2. 四种常见组合

组合 maxSurge maxUnavailable 行为 适用场景
稳妥型 1 0 先建新Pod再缩旧Pod,零中断 核心业务推荐
平衡型 1 1 新建1个同时缩1个,资源占用不变 日常迭代
激进型 25% 25% 快速替换,可能有短暂不可用 非关键服务
最激进 0 1 不多建Pod,先缩旧再建新 资源紧张时

实战调优建议:

  • 核心业务 (支付、订单):maxSurge: 1, maxUnavailable: 0,宁可多用资源也要零中断
  • 一般业务maxSurge: 25%, maxUnavailable: 1,平衡速度和可用性
  • 资源紧张maxSurge: 0, maxUnavailable: 1,不多占资源但会有短暂不可用
bash 复制代码
# 查看当前更新策略
kubectl get deployment nginx -o jsonpath='{.spec.strategy}'

# 修改策略
kubectl patch deployment nginx -p '{"spec":{"strategy":{"rollingUpdate":{"maxSurge":1,"maxUnavailable":0}}}}'

四、更新暂停与继续:rollout pause / resume

有时候我们不想一次性完成更新------比如灰度观察、分批发布。Deployment 支持暂停滚动更新

bash 复制代码
# 触发更新并立即暂停(只更新1个Pod就停住)
kubectl set image deployment/nginx nginx=nginx:1.30.1
kubectl rollout pause deployment/nginx

# 此时只有1个新Pod被创建,其余仍是旧版本
kubectl get pods
# nginx-5b8d7c6e2a-abc   1/1   Running   ← 新版(1个)
# nginx-7f6b5d4cf9-xyz   1/1   Running   ← 旧版(3个)

# 观察一段时间后,继续更新
kubectl rollout resume deployment/nginx

# 更新继续,剩余旧Pod逐步替换

典型场景:

  • 灰度验证:pause 后只1个新Pod在跑,观察日志和指标,没问题再 resume
  • 分批发布:pause → 观察 → resume → 再 pause → 再观察,手动控制节奏
  • 紧急刹车:更新过程中发现问题,pause 暂停,确认后 resume 或回滚

注意:

  • pause 期间 Deployment 处于暂停状态,kubectl rollout status 会提示 deployment "nginx" is paused
  • resume 后会从暂停的位置继续,不会从头开始
  • pause 只对 RollingUpdate 有效,Recreate 策略下没意义(旧Pod已经全杀了)

一句话总结: 按下了一个"暂停键",让 Nginx 的版本升级过程卡在当前进度,方便你先观察新 Pod 的表现,确定没问题后再按"继续键"(resume)。这是在生产环境做精细化流量验证的保命手段。

五、回滚:rollout undo 与 --to-revision

1. 快速回滚到上一版本

bash 复制代码
# 回滚到上一个版本
kubectl rollout undo deployment/nginx

# 查看回滚状态
kubectl rollout status deployment/nginx

回滚的本质是什么?把旧 RS 的副本数从0扩回3,新 RS 的副本数缩为0。Pod 不需要重建,只是 RS 的 desired replicas 被修改------这也是回滚是"秒级"的原因。

2. 查看历史版本

bash 复制代码
# 查看所有历史revision
kubectl rollout history deployment/nginx

# 查看某个revision的详细信息
kubectl rollout history deployment/nginx --revision=2

**注意:**推荐用 annotation 记录变更原因:

bash 复制代码
# 设置变更原因
kubectl annotate deployment/nginx kubectl.kubernetes.io/change-cause="升级到1.30.1修复安全漏洞"

3. 回滚到指定版本

bash 复制代码
# 回滚到 revision 5
kubectl rollout undo deployment/nginx --to-revision=5

# 确认当前版本
kubectl rollout history deployment/nginx
# 注意:回滚后revision编号会继续递增,不会回到5

关键细节:

  • 回滚后的 revision 编号是新的(继续递增),不是回到旧的编号
  • revisionHistoryLimit(默认10)限制保留的旧 RS 数量,超过限制的 revision 无法回滚
  • 如果你想回滚到某个已被清理的版本------回不了,只能重新 apply 对应的 YAML

4. 实战回滚流程

bash 复制代码
# 1. 发现问题,先暂停更新(可选)
kubectl rollout pause deployment/nginx

# 2. 查看历史版本,找到要回滚的revision
kubectl rollout history deployment/nginx

# 3. 看目标revision的详细配置
kubectl rollout history deployment/nginx --revision=5

# 4. 回滚
kubectl rollout undo deployment/nginx --to-revision=5

# 5. 确认回滚成功
kubectl rollout status deployment/nginx
kubectl get pods -l app=nginx

上集小结

上集我们从 Deployment 是什么、三级结构讲到了滚动更新策略调优、pause/resume 灰度验证和回滚全流程。核心记住三件事:

  • 旧 RS 不删是回滚的前提,回滚的本质就是把旧 RS 扩回来
  • maxSurge=1, maxUnavailable=0 是核心业务的最稳妥组合
  • pause + resume 是灰度的保命手段,出问题先 pause 再决定回滚

到这里,日常滚动发布 + 紧急回滚你已经有完整的武器库了。下一集我们上强度------蓝绿部署和灰度发布,以及日常运维排坑,把 Deployment 的功力彻底打透。

👉 下集预告:Deployment 蓝绿部署与灰度发布:高级策略与排坑实战(下)