核对上下文、命名空间、Deployment、目标版本和当前已验证版本。
外观
外观
约 3099 字大约 10 分钟
KubernetesDeploymentRollingUpdaterollout
2026-07-30
[Windows PowerShell] wsl ~:打开本机默认的 WSL2 Ubuntu;本课继续使用本地隔离集群,不需要 SSH 登录 ECS,运行 kubectl 前先核对当前集群上下文。第 15 次课把一个 Deployment 扩到三个副本。现在要回答更接近生产运维的问题:页面升级时,怎样逐步替换旧 Pod;新版本拉不起镜像时,怎样保住正在服务的旧版本;确认故障后,怎样回到最后一个已经验证的修订。
关键提醒
提交新清单不等于发布完成。完整结论至少需要修订可追踪、滚动过程结束、副本就绪、Service 路径返回目标版本;失败时还要保留故障证据并完成回滚回归。
学完这一课,做到五件事:
maxUnavailable、maxSurge 与 readiness 对滚动发布的影响。rollout status、history 和实际请求验收。先发布并验证 v1,再滚动到 v2。每次变更都要留下修订说明、发布状态、副本状态和页面版本,后续才能判断应该回到哪一个修订。
错误镜像案例只作用于本课命名空间。发现发布超时后,先读取 Pod 事件和旧副本状态,再决定是否回滚;不要靠删除 ReplicaSet 清空历史。
第 15 次课使用的测试集群已完成清理。本课统一使用全新的 xpk-lesson16 集群,独立命名空间为 cloud-course-16。前后两次课程互不干扰,不共享 Pod、Service 或历史版本。
先创建隔离集群并将清单文件部署到工作目录:
[WSL] k3d cluster create xpk-lesson16 --servers 1 --agents 0
[WSL] mkdir -p ~/cloud-course/lab-16
[WSL] cp -r /path/to/lab-16-starter/* ~/cloud-course/lab-16/
[WSL] cd ~/cloud-course/lab-16实训包清单文件在 manifests/ 子目录中(从智慧职教课程资源区下载 lab-16-starter.zip 解压)。
[WSL] kubectl config current-context核对当前的集群上下文。如果连接的目标不对,先停止操作,确认指向无误后再继续。
[WSL] kubectl get nodes确认 Node 处于 Ready 状态。节点就绪是基础支撑,应用发布是否成功还得继续检查。
[WSL] kubectl get namespace cloud-course-16首次运行前预期返回 NotFound,这正好说明当前环境干净,没有任何历史残留。
安全边界
本课仅限定在 cloud-course-16 命名空间内部操作。切勿改动 kube-system,严禁随意删除其他命名空间,也不要把异常镜像测试带入公共环境。
Deployment 并不直接逐个创建或销毁 Pod,而是通过管理不同的 ReplicaSet(副本集——负责维护指定数量 Pod 副本的控制器)来控制版本。一旦 Pod 模板发生变更,Deployment 就会拉起一个新的 ReplicaSet:
Deployment lesson16-web
├── ReplicaSet revision 1 → v1 Pod 模板
├── ReplicaSet revision 2 → v2 Pod 模板
└── ReplicaSet revision 3 → 错误镜像 Pod 模板集群里的修订历史并不是完整的代码仓库,它记录的是 Deployment 在不同阶段的 Pod 模板快照,最大保留数量由 revisionHistoryLimit 决定。本课设为 5,足够保留演练所需的历史节点。
metadata:
annotations:
kubernetes.io/change-cause: "lesson16 release v2"change-cause 负责给历史版本打上人类可读的备注。发布时应当随清单一同更新,方便日后准确溯源。
[WSL] kubectl rollout history deployment/lesson16-web -n cloud-course-16查看各版本 Revision 编号与对应的 CHANGE-CAUSE。这能帮我们精准指定要回滚的目标版本。
从变更意图、滚动状态、修订历史、工作负载和用户路径组织发布与回滚证据。
核对上下文、命名空间、Deployment、目标版本和当前已验证版本。
本课的 Deployment 设置了 3 个 Pod 副本:
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1参数的具体含义如下:
| 参数 | 本课值 | 含义 | 代价 |
|---|---|---|---|
maxUnavailable | 0 | 更新期间不主动让可用副本少于 3 | 坏版本可能让发布停住 |
maxSurge | 1 | 最多临时多创建 1 个 Pod | 需要额外 CPU、内存和 IP |
readinessProbe 决定新 Pod 何时进入可用副本。若新 Pod 镜像拉取失败或探针不通过,控制器不会把它算作 Ready。
readinessProbe:
httpGet:
path: /
port: http每个新 Pod 都要能在容器内通过 / 路径的 HTTP 检查。探针成功只说明这条内部就绪路径正常,还要通过 Service 读取发布版本。
观看时留意:滚动更新期间,新旧 ReplicaSet 和 Pod 为什么会同时存在?
与本课的关系:更新过程要结合 rollout status、Pod 状态和用户路径观察,不能只看命令返回。
关键提醒
maxUnavailable: 0 可以帮助保留当前可用副本,但它不是“永不中断”保证。节点故障、资源不足、应用共享依赖和错误的探针设计仍可能造成中断。
首先创建 Namespace、v1 内容、Service 与 v1 Deployment:
[WSL] kubectl apply \
-f manifests/namespace.yaml \
-f manifests/configmap-v1.yaml \
-f manifests/service.yaml \
-f manifests/deployment-v1.yaml提交 v1 的期望状态。输出的 created/configured 只代表 API 接受了请求。
[WSL] kubectl rollout status deployment/lesson16-web \
-n cloud-course-16 --timeout=120s等待三个 v1 副本就绪。
[WSL] kubectl exec -n cloud-course-16 deploy/lesson16-web -- \
wget -q -O - http://lesson16-web | grep 'release='通过 Service 读取页面版本,v1 基线应返回 release=v1。
准备发布 v2:
[WSL] kubectl apply \
-f manifests/configmap-v2.yaml \
-f manifests/deployment-v2.yaml创建版本化 ConfigMap,并把 Pod 模板的版本标签和挂载改为 v2。Pod 模板改变后,Deployment 创建新 ReplicaSet。
[WSL] kubectl rollout status deployment/lesson16-web \
-n cloud-course-16 --timeout=120s观察新 Pod 逐步就绪、旧 Pod 逐步退出,直到显示 successfully rolled out。
[WSL] kubectl rollout history deployment/lesson16-web -n cloud-course-16预期修订 1 为 lesson16 release v1,修订 2 为 lesson16 release v2。
[WSL] kubectl get deployment,replicaset,pods \
-n cloud-course-16 -l app.kubernetes.io/name=lesson16-web -o wideDeployment 应为 3/3;v2 ReplicaSet 维护三个就绪 Pod,v1 ReplicaSet 缩为 0。
教师机本地 k3d/K3s 隔离集群 · 2026-07-28 真实发布
teacher@local:lab-16$ kubectl apply -f configmap-v2.yaml -f deployment-v2.yamlconfigmap/lesson16-web-v2 createddeployment.apps/lesson16-web configured“应用 Kubernetes 资源”保留了完整命令和与它相邻的输出。判断时应直接引用输出中的字段或状态,不要把步骤名称当成结论。
这一步是“v2 滚动发布成功,历史包含 v1/v2,Deployment 达到 3/3,Service 返回 release=v2”证据链中的一环。
只证明本地单节点教学集群的这次发布,不证明生产无损升级或长期稳定

整页截图与上方分步卡片来自同一条记录;敏感字段已经遮盖,较长命令可能经过换行排版。
这里故意使用一个不存在的教学镜像标签来模拟故障。说明和 Pod 模板变更放在同一个 strategic patch 中:
[WSL] kubectl patch deployment lesson16-web -n cloud-course-16 \
--type=strategic \
-p '{"metadata":{"annotations":{"kubernetes.io/change-cause":"lesson16 fault invalid image"}},"spec":{"template":{"spec":{"containers":[{"name":"web","image":"nginx:lesson16-missing"}]}}}}'这条命令只修改本课 Deployment。它会创建新的错误修订,不改变 v2 ConfigMap,也不删除旧 ReplicaSet。
[WSL] kubectl rollout status deployment/lesson16-web \
-n cloud-course-16 --timeout=15s本课预期命令会超时并返回非 0。超时本身就是故障证据,不要试图通过延长等待时间来假装问题会自行消失。
[WSL] kubectl get deployment,pods \
-n cloud-course-16 -l app.kubernetes.io/name=lesson16-web -o wide真实结果中 Deployment 显示 READY 仍为 3/3、UP-TO-DATE 为 1、AVAILABLE 为 3;三个旧 v2 Pod 仍 Running,新 Pod 会先出现 ErrImagePull,重试后进入 ImagePullBackOff。说明:
maxUnavailable: 0 让三个已就绪 v2 Pod 保持服务;先定位那个拉镜像失败的 Pod。如果你能直接从 kubectl get pods 的输出中认出异常 Pod 的名字,直接用名字即可。想用命令自动筛选的话,下面是 jsonpath 的拆解——先看懂每一步在做什么,不要整段照抄:
[WSL] fault_pod="$(kubectl get pods -n cloud-course-16 \
-l app.kubernetes.io/name=lesson16-web \
-o jsonpath='{range .items[?(@.status.containerStatuses[0].ready==false)]}{.metadata.name}{"\n"}{end}' \
| head -n 1)"
[WSL] kubectl describe pod -n cloud-course-16 "$fault_pod"jsonpath 表达式分四步读:① range .items[] 遍历 Pod 列表;② [?(@.status.containerStatuses[0].ready==false)] 筛选第一个容器尚未就绪的 Pod;③ .metadata.name 输出 Pod 名;④ end 结束遍历。-l 标签选择器已经把范围限定在本课 Deployment 的 Pod,所以最终取到的是本课那个拉镜像失败的 Pod。Events 中的 Failed to pull image、not found 能把范围进一步缩小到镜像引用或仓库访问。
[WSL] kubectl rollout history deployment/lesson16-web -n cloud-course-16预期出现第三条 lesson16 fault invalid image,为后续选择回滚目标提供依据。
cloud-course-16 隔离命名空间 · 2026-07-28 真实故障
...$ kubectl patch deployment lesson16-web -n cloud-course-16 \
--type=strategic -p \
'{"metadata":{"annotations":{"kubernetes.io/change-cause":"lesson16 fault invalid image"}},
"spec":{"template":{"spec":{"containers":[{"name":"web","image":"nginx:lesson16-missing"}]}}}}}'deployment.apps/lesson16-web patched“注入错误镜像”保留了完整命令和与它相邻的输出。判断时应直接引用输出中的字段或状态,不要把步骤名称当成结论。
这一步是“错误镜像修订超时,新 Pod 为 ImagePullBackOff,事件显示标签不存在,同时三个旧 v2 副本和页面仍可用”证据链中的一环。
不能保证所有发布故障都保留旧版本,也不证明镜像仓库整体不可用

整页截图与上方分步卡片来自同一条记录;敏感字段已经遮盖,较长命令可能经过换行排版。
输入脱敏后的 rollout、history、ReplicaSet、Pod、事件和页面结果,让助教判断应等待、修复还是回滚。
本实验的原始聊天仅保存在当前标签页,不会写入全局课程助教上下文。
当前历史为:
| 修订 | 说明 | 案例结论 |
|---|---|---|
| 1 | release v1 | 曾通过基线 |
| 2 | release v2 | 最后一个完整验收版本 |
| 3 | fault invalid image | 发布失败 |
本课明确回到修订 2:
[WSL] kubectl rollout undo deployment/lesson16-web \
-n cloud-course-16 --to-revision=2--to-revision=2 避免只凭“上一版”猜测目标。命令返回 rolled back 只说明回滚请求已提交。
[WSL] kubectl rollout status deployment/lesson16-web \
-n cloud-course-16 --timeout=120s等待回滚后的 Deployment 完成。
[WSL] kubectl get deployment lesson16-web -n cloud-course-16 \
-o jsonpath='image={.spec.template.spec.containers[0].image}{" version="}{.spec.template.metadata.labels.app\.kubernetes\.io/version}{"\n"}'检查当前模板恢复为 nginx:1.27-alpine 和 version=v2。
[WSL] kubectl exec -n cloud-course-16 deploy/lesson16-web -- \
wget -q -O - http://lesson16-web | grep 'release='沿原 Service 路径应再次返回 release=v2。
[WSL] kubectl rollout history deployment/lesson16-web -n cloud-course-16回滚后,原修订 2 的模板会成为新的修订 4,因此历史通常显示 1、3、4,而不是直接抹除中间的修订记录。修订 4 的 CHANGE-CAUSE 仍是 release v2。
从错误修订 3 回到已验证 v2 · 2026-07-28 真实运行
...$ kubectl rollout undo deployment/lesson16-web \
-n cloud-course-16 --to-revision=2deployment.apps/lesson16-web rolled back“回滚到指定版本”保留了完整命令和与它相邻的输出。判断时应直接引用输出中的字段或状态,不要把步骤名称当成结论。
这一步是“回滚成功并生成修订 4,Deployment 3/3,镜像和 v2 标签恢复,Service 返回 release=v2”证据链中的一环。
只覆盖 Deployment Pod 模板与本课页面,不证明 ConfigMap 对象、Service、数据库或外部系统已回滚

整页截图与上方分步卡片来自同一条记录;敏感字段已经遮盖,较长命令可能经过换行排版。
观看时留意:回滚目标怎样和历史修订对应,回滚后还要检查哪些实际状态?
与本课的关系:回滚 Deployment 不能恢复数据库和外部数据,本课会单独检查它的边界。
Deployment 回滚主要恢复 Pod 模板:
| 内容 | 本课是否由 Deployment 回滚 | 说明 |
|---|---|---|
| 容器镜像 | 是 | 位于 Pod 模板 |
| Pod 标签 | 是 | 位于 Pod 模板 |
| 探针与资源限制 | 是 | 位于 Pod 模板 |
| 版本化 ConfigMap 引用 | 是 | volume 引用位于 Pod 模板 |
| ConfigMap 对象内容 | 否 | 独立 API 对象,需要版本化或另行恢复 |
| Service | 否 | 独立 API 对象 |
| 数据库结构与数据 | 否 | 需要独立迁移和恢复方案 |
因此“Deployment 已回滚”不能直接写成“整个系统已经回滚”。真实项目还要检查数据库兼容、缓存、消息、外部 API 和配置版本。
观看时留意:容器活着和 Pod 可以接收流量分别由哪类探针判断?
与本课的关系:探针配置错误也会制造故障。参数必须结合应用真实启动时间和健康端点设置。
[WSL] bash verify.sh自动脚本检查当前上下文、三个就绪副本、v2 标签、正确镜像、三个端点、修订历史和 Service 页面。
检查发布基线、修订说明、故障证据、回滚目标、同路回归和清理边界。
[WSL] bash cleanup.sh脚本只删除 cloud-course-16 命名空间,并确认查询该空间时返回 NotFound。案例结束后再删除本课 k3d 集群。
[WSL] kubectl get namespaces确认其他命名空间仍在。不要清理所有 ReplicaSet、镜像或集群系统组件。
完整步骤见实训 16:Kubernetes 滚动发布、故障与回滚。
提交文件名:
班级_学号_姓名_第16次课_Kubernetes发布回滚报告.docx只提交一个 Word 到智慧职教“第16次课”。不要上传 kubeconfig、令牌、证书、完整地址、完整事件全集或其他命名空间数据。
用 6 道题检查滚动策略、修订历史、故障状态、回滚选择和恢复边界。
maxUnavailable: 0 和 maxSurge: 1 控制滚动交接,但不承诺任何场景都无中断。rollout status 成功、修订历史、三个副本就绪和 Service 版本请求共同构成发布证据。下一次课将从 WSL 通过 Ansible 管理云主机 B,并用重复执行与健康检查验证自动化是否幂等。
以下资料在 2026-07-28 核对:
助教会读取当前课程页面和结构化学习记录,但不会读取正文实验框里的原始聊天。