外观
第六节 无状态应用发布与回滚
约 3138 字大约 10 分钟
KubernetesDeploymentReplicaSetRollingUpdate
2026-07-28
项目目标
将独立的 Web Pod 升级为具备声明式自愈、弹性扩缩容、零停机滚动更新与版本回滚能力的 Deployment 对象 yunfan-web.yaml;深入理解 Deployment → ReplicaSet → Pod 三层层级控制链与 pod-template-hash 命名原理;掌握 maxSurge / maxUnavailable 的数量浮动算式,并完成发布、错误镜像停滞诊断与 rollout undo 历史回滚闭环。
6.1 架构控制链:Deployment、ReplicaSet 与 Pod 的三层关系
在上一课中,我们部署了独立的 Pod。然而,独立 Pod 一旦遭遇宿主机故障或被误删,不会自动重建。在生产环境中,无状态应用(Stateless Applications)需要具备自愈和滚动扩缩的能力。
在 Kubernetes 中,管理无状态应用的标准控制器是 Deployment。
6.1.1 三层控制链与 pod-template-hash
Deployment 并不直接去操控或创建具体的 Pod 容器,而是通过 ReplicaSet 进行层级间接控制:
- Deployment(发布控制器):负责管理 Pod 的模板版本(Pod Template)、发布策略(RollingUpdate)与版本修订历史(Revision History)。
- ReplicaSet(副本集控制器):负责维护匹配特定的选择器(Selector)的 Pod 期望副本数量(Replicas)。当某个 Pod 消失时,ReplicaSet 负责补出新 Pod。
- Pod(运行实例):真正承载业务容器的运行单元。
解密 Pod 的命名规则: 当你运行 kubectl get pods 时,会看到 Pod 的名称类似于 yunfan-web-74b889895-a1b2c。
yunfan-web: Deployment 的名称。74b889895:pod-template-hash。这是根据 Pod 模板(spec.template)内容计算出的唯一 Hash 值,也是它所属的 ReplicaSet 的名字!a1b2c: ReplicaSet 为该特定 Pod 实例生成的随机后缀。
观察下面的交互面板,理解 Deployment 如何通过控制 ReplicaSet 来间接保持 Pod 数量:
Deployment 怎样间接管理 Pod
观察 Deployment、ReplicaSet 与 Pod 的控制链。
1 / 5
6.2 配置文件编写:声明式 yunfan-web.yaml
在项目根目录下直接创建 Deployment 配置文件 yunfan-web.yaml。
6.2.1 完整配置文件:yunfan-web.yaml
yunfan-web.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: yunfan-web
namespace: yunfan-shop
labels:
app.kubernetes.io/name: yunfan-web
app.kubernetes.io/part-of: yunfan-mall
spec:
replicas: 3
revisionHistoryLimit: 5
progressDeadlineSeconds: 120
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
selector:
matchLabels:
app.kubernetes.io/name: yunfan-web
template:
metadata:
labels:
app.kubernetes.io/name: yunfan-web
app.kubernetes.io/part-of: yunfan-mall
tier: frontend
env: lab
spec:
containers:
- name: nginx
image: nginx:1.27-alpine
resources:
requests:
cpu: 50m
memory: 32Mi
limits:
cpu: 200m
memory: 128Mi
ports:
- name: http
containerPort: 80在终端中应用该配置文件:
kubectl apply -f yunfan-web.yaml
kubectl rollout status deployment/yunfan-web -n yunfan-shop --timeout=120s6.2.2 滚动更新策略与关键参数算式解析
strategy.type: RollingUpdate(滚动更新):- 在更新应用时,逐步创建新版本的 Pod 并逐步销毁旧版本的 Pod,实现 零停机时间(Zero-Downtime)。相比之下,
type: Recreate会先杀光所有旧 Pod 再创建新 Pod,会导致服务中断。
- 在更新应用时,逐步创建新版本的 Pod 并逐步销毁旧版本的 Pod,实现 零停机时间(Zero-Downtime)。相比之下,
maxSurge: 1与maxUnavailable: 1算式:maxSurge(最大超额量):发布过程中,允许临时比期望副本数(replicas: 3)多出的 Pod 数量上限。本例中最高允许总 Pod 数达到3 + 1 = 4个。maxUnavailable(最大不可用量):发布过程中,允许临时处于非就绪状态或被销毁的 Pod 数量上限。本例中最低保证可用 Pod 数不低于3 - 1 = 2个。
revisionHistoryLimit: 5:- 保留最近 5 个历史 ReplicaSet 修订版本(Revision),以便于后续执行
kubectl rollout undo一键回滚。
- 保留最近 5 个历史 ReplicaSet 修订版本(Revision),以便于后续执行
progressDeadlineSeconds: 120:- 判定发布卡死的超时阀值。如果发布过程超过 120 秒仍未完成,Deployment 会在 Status 中标注
ProgressDeadlineExceeded。
- 判定发布卡死的超时阀值。如果发布过程超过 120 秒仍未完成,Deployment 会在 Status 中标注
运行以下命令,同时查看三层对象的运行状态:
kubectl get deployment,replicaset,pod -n yunfan-shop -o wide6.3 运维实训:弹性扩缩容与声明式自愈
6.3.1 副本动态扩缩容 (Scale)
当流量突增或降低时,可以随时调整 Deployment 的副本数量。
1. 命令式调整副本:
# 将副本数缩容到 2
kubectl scale deployment/yunfan-web -n yunfan-shop --replicas=2
kubectl get pod -n yunfan-shop -l app.kubernetes.io/name=yunfan-web
# 将副本数扩容会 3
kubectl scale deployment/yunfan-web -n yunfan-shop --replicas=3
kubectl rollout status deployment/yunfan-web -n yunfan-shop原理解析: 运行 kubectl scale 调整副本数时,只改变了 ReplicaSet 的 spec.replicas 属性,没有修改 Pod 模板(spec.template),因此不会触发新 Revision 历史版本的创建。
6.3.2 声明式自愈能力测试
手动删除其中的一个 Pod,验证 ReplicaSet 的自愈机制:
# 获取当前 Pod 列表
kubectl get pod -n yunfan-shop -l app.kubernetes.io/name=yunfan-web
# 随意删除其中一个 Pod
kubectl delete pod -n yunfan-shop <其中一个-pod-name>
# 实时观察 Pod 状态变化
kubectl get pod -n yunfan-shop -l app.kubernetes.io/name=yunfan-web -w关键观察点: 被删除的旧 Pod 状态变为 Terminating,而 ReplicaSet 会在毫秒级时间内检测到期望副本数不满足,并立即创建一个全新的 Pod!新 Pod 的名称后缀与 UID 会发生改变,但 Deployment 与 ReplicaSet 依然保持稳定性。
6.4 版本发布:滚动更新与 ReplicaSet 交接
当业务需要升级镜像或修改环境变量时,通过更新 Deployment 的 Pod 模板来触发滚动更新。
观察下面的滚动更新动画,理解新 ReplicaSet 如何逐步放大、旧 ReplicaSet 如何逐步缩小:
滚动更新如何替换版本
同时观察新旧 ReplicaSet 与可用副本。
1 / 5
6.4.1 滚动更新实操
1. 添加变更注解并更新镜像:
# 添加变更原因注解 (记录在 history 中)
kubectl annotate deployment/yunfan-web \
-n yunfan-shop \
kubernetes.io/change-cause="升级 Nginx 镜像到 1.28-alpine" \
--overwrite
# 修改镜像触发滚动更新
kubectl set image deployment/yunfan-web \
-n yunfan-shop \
nginx=nginx:1.28-alpine2. 观察滚动更新过程与历史记录:
# 观察发布状态
kubectl rollout status deployment/yunfan-web -n yunfan-shop --timeout=120s
# 查看发布历史版本记录
kubectl rollout history deployment/yunfan-web -n yunfan-shop
# 查看 ReplicaSet 列表
kubectl get replicaset -n yunfan-shop预期观察: 你会看到系统保留了两个 ReplicaSet。旧的 ReplicaSet 副本数被缩小为 0,全新的 ReplicaSet 副本数增长为 3。
6.5 故障演练:错误镜像停滞与 rollout undo 回滚
在实际生产中,发布可能会因镜像 tag 写错或代码崩溃而停滞。我们需要掌握如何诊断卡住的发布并执行一键回滚。
6.5.1 触发错误镜像发布
故意更新为一个不存在的镜像版本:
# 记录故障变更原因
kubectl annotate deployment/yunfan-web \
-n yunfan-shop \
kubernetes.io/change-cause="故意引入错误镜像进行回滚测试" \
--overwrite
# 更新为一个不存在的镜像 tag
kubectl set image deployment/yunfan-web \
-n yunfan-shop \
nginx=nginx:not-exist观察发布停滞:
# 查看发布状态 (会在 60 秒后超时)
kubectl rollout status deployment/yunfan-web -n yunfan-shop --timeout=60s此时查看 Pod 和 ReplicaSet 状态:
kubectl get pod,replicaset -n yunfan-shop
kubectl describe deployment yunfan-web -n yunfan-shop原理分析: 由于 maxUnavailable: 1 的保护,系统最多允许 1 个 Pod 不可用。旧的 ReplicaSet 依然保持着 2 个健康的旧 Pod 在对外提供服务;而新 ReplicaSet 创建出的 1 个 Pod 会卡在 ImagePullBackOff 状态。发布过程安全地卡住了,不会将所有 Pod 一下子全部弄挂。
6.5.2 执行一键版本回滚 (rollout undo)
确认发布故障后,使用 rollout undo 撤销发布,恢复到上一个稳定版本:
# 撤销本次失败的发布,回滚到上一个 Revision
kubectl rollout undo deployment/yunfan-web -n yunfan-shop
# 验证回滚状态
kubectl rollout status deployment/yunfan-web -n yunfan-shop --timeout=120s验证回滚后的当前镜像:
kubectl get deployment yunfan-web -n yunfan-shop \
-o jsonpath='{.spec.template.spec.containers[0].image}{"\n"}'预期输出:镜像恢复为之前的 nginx:1.28-alpine。
若要回滚到特定的历史版本,可以先通过 kubectl rollout history 查看版本号,再指定 --to-revision:
# 回滚到指定的历史版本 (如 Revision 1)
kubectl rollout undo deployment/yunfan-web -n yunfan-shop --to-revision=16.6 高级技巧:发布暂停、恢复与重启
6.6.1 暂停与恢复发布 (pause / resume)
当你需要对 Deployment 的 Pod 模板进行多项修改(如同时修改镜像、环境变量和资源限制)时,可以先暂停发布,避免每次修改都触发一次不必要的滚动更新:
# 1. 暂停 Deployment 的发布响应
kubectl rollout pause deployment/yunfan-web -n yunfan-shop
# 2. 连续执行多项修改 (此时不会触发更新)
kubectl set resources deployment/yunfan-web \
-n yunfan-shop \
-c nginx \
--requests=cpu=60m,memory=40Mi \
--limits=cpu=200m,memory=128Mi
# 3. 恢复发布,一次性生效所有变更
kubectl rollout resume deployment/yunfan-web -n yunfan-shop
kubectl rollout status deployment/yunfan-web -n yunfan-shop6.6.2 触发平滑重启 (rollout restart)
如果需要刷新所有 Pod(如业务应用需要重新读取 ConfigMap),无需修改镜像,直接运行重启命令:
kubectl rollout restart deployment/yunfan-web -n yunfan-shop
kubectl rollout status deployment/yunfan-web -n yunfan-shop底层原理:rollout restart 会自动在 Pod 模板的 metadata.annotations 中注入当前时间戳(kubectl.kubernetes.io/restartedAt),由于 Pod 模板发生了改变,系统会无缝地进行一次零停机平滑滚动重启。
6.7 阶段验收与排错速查
6.7.1 发布事件线模板
在运维实践中,整理发布事件线有助于复盘:
| 时间节点 | 操作动作 | 系统状态与 ReplicaSet 表现 | 运维决策与结果 |
|---|---|---|---|
| T0 | 初始部署 1.27-alpine | 创建 RS-1,3/3 Pod 就绪 | 建立稳定基线 Revision 1 |
| T1 | 升级到 1.28-alpine | 创建 RS-2,RS-2 扩容至 3,RS-1 缩容至 0 | 发布成功,生成 Revision 2 |
| T2 | 误操作升级 not-exist | 创建 RS-3,1 Pod ImagePullBackOff;旧 RS-2 保持 2 Pod | 触发 maxUnavailable 拦截保护 |
| T3 | 执行 rollout undo | RS-3 被删除,RS-2 重新扩容至 3 | 成功回滚至 Revision 2 稳定状态 |
6.7.2 本课提交成果清单
完成本课实训后,提交以下三项成果即可:
- 配置文件:项目根目录下的
yunfan-web.yaml。 - 第一张截图
06-control-chain.png:同一终端画面中包含kubectl get deployment,replicaset,pod -n yunfan-shop -o wide展示三层层级控制链。 - 第二张截图
06-rollout-undo.png:同一终端画面中包含kubectl rollout history、错误镜像卡住的 Pod 状态以及执行rollout undo成功恢复的结果。
6.7.3 常见错误与排错矩阵
| 故障现象 | 可能原因 | 修复排查路径 |
|---|---|---|
rollout status 长时间卡住 | 镜像不存在、limits 资源不足或探测失败 | 运行 kubectl get pods 找出卡住的 Pod;用 describe pod 查看 Events 确切原因。 |
rollout undo 提示找不到 Revision | revisionHistoryLimit 设置过小导致旧 RS 被清理 | 确认 rollout history;若旧 RS 已清空,使用 kubectl apply -f 重新应用备份的 YAML。 |
| 两个控制器争抢同一个 Pod | 不同 Deployment 的 spec.selector 标签重叠 | 检查各 YAML 文件的 selector.matchLabels,确保不同应用的标签相互独立。 |
| 修改了配置但未触发滚动更新 | 仅修改了 replicas 数量或非模板字段 | 确认是否改动了 spec.template;若需强制重启,运行 kubectl rollout restart。 |
挑战任务:探秘 pod-template-hash 的作用
运行 kubectl get rs -n yunfan-shop --show-labels,观察每一个 ReplicaSet 上的标签。尝试解释:为什么每个 ReplicaSet 和它创建的 Pod 上都会自动被注入一个 pod-template-hash 标签?如果没有这个 Hash 标签,当两个 Deployment 使用相同的业务标签时会发生什么?
本章小测
本章小结
完成本课后,你已经掌握了:
- 三层控制链架构:理解了 Deployment → ReplicaSet → Pod 的层级控制关系,以及
pod-template-hash保证模板与副本集对应的机制。 - 滚动更新与算式逻辑:掌握了
strategy.type: RollingUpdate的工作流,能够通过maxSurge和maxUnavailable精确计算发布过程中的 Pod 数量上限与下限。 - 弹性扩缩与声明式自愈:理解了
kubectl scale不增加 Revision 的原因,验证了 ReplicaSet 维持期望副本数自动补齐 Pod 的自愈能力。 - 版本发布与历史回滚:熟练掌握了
kubectl set image、rollout history以及kubectl rollout undo(含--to-revision)在故障时的止损回滚。 - 批处理与平滑重启:掌握了
rollout pause/resume合并变更与rollout restart通过修改模板注解平滑重建 Pod 的高级技巧。
下一课中,我们将为 yunfan-web 引入 Service 服务发现与负载均衡,解决 Pod IP 动态变化时的稳定访问与 NodePort 外部接入问题!
