Deployment 滚动更新与回滚:从原理到手操(上)
我们每天都在 kubectl apply 更新镜像版本,然后等 Pod 一个个替换完。但你真的了解 apply 之后发生了什么吗?
- Deployment 更新时,不是直接改 Pod,而是创建新 ReplicaSet(RS),逐步用新 RS 的 Pod 替换旧 RS 的 Pod
- 旧 RS 不会立刻删除------它是你回滚的"安全绳"
maxSurge和maxUnavailable两个参数,决定了更新过程有多激进还是多保守
上集聚焦 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 的功力彻底打透。