部署、弄坏、再回滚
目标
让部署变得可以回滚。完成一整轮操作:部署、故意破坏、用两种方式恢复,以及解救卡住的 release。
为什么重要
部署自动化的成败,不是由成功时决定,而是由失败后会留下什么状态决定。helm upgrade 默认不会检查 Pod 是否真正启动,就会返回成功。因此可能出现 CI 显示绿色,只有用户遭遇故障的情况。
本实验会亲手制造这种情况。第 4 步部署不存在的 image 后,你会亲眼看到 helm 显示 STATUS: deployed。随后再比较添加 --atomic 后会发生什么变化。
环境
此 Pod 使用 kwok 启动真实 kube-apiserver。Pod 不会真正运行,但 release Secret、revision 与 resource 变更都是真实的。因此评分器也会重新读取 cluster 状态,而不是检查文件。
kubectl get nodes 노드 2대가 Ready
helm version v3.16
步骤
helm create demo→helm install- 从 release Secret 中提取 manifest,保存到
/root/helm/02-manifest.yaml - 使用
--set replicaCount=4创建 revision 2 - 使用不存在的 image 执行 upgrade,确认它仍显示成功
- 对同一错误添加
--atomic→/root/helm/05-atomic.txt helm rollback demo 2- 对两次
helm template的结果执行 diff →/root/helm/07-diff.txt - 解救卡在 pending-upgrade 状态的 release
参考
- 本实验有些步骤中,命令失败才是正确结果(第 5 步)。目标是保存失败输出。
- 经常查看
helm history demo。所有已发生的事情都记录在那里。 - release 卡住通常发生在 helm process 中途终止或 CI 被取消时。
创建并部署 chart
helm create demo → helm install
使用 helm create demo 创建 scaffold,再用 helm install demo ./demo 部署。只要在 helm list 中显示为 deployed 即可。该 cluster 使用 kwok,因此 Pod 不会真正运行,但 release、revision 与 resource 都是真实的。
直接查看保存 release 的 Secret
从 release Secret 中提取 manifest,保存到 /root/helm/02-manifest.yaml
使用 kubectl get secret -l owner=helm 确认名称。按照 -o jsonpath='{.data.release}' → base64 -d → base64 -d → gzip -d 的顺序解开,会得到完整 release JSON,而不是 manifest。render 后的 YAML 以字符串形式存放在该 JSON 的 .manifest 字段中,请用 jq -r .manifest 提取并保存到 /root/helm/02-manifest.yaml。
提高 replicas,创建 revision 2
使用 --set replicaCount=4 创建 revision 2
执行 helm upgrade demo ./demo --set replicaCount=4。然后用 helm history demo 确认已有两个 revision,并确认 revision 1 已变为 superseded。
故意破坏部署
使用不存在的 image 执行 upgrade,并确认它仍显示成功
尝试使用不存在的 image upgrade:--set image.repository=nope/nothing --set image.tag=v0。不添加 --wait 时,helm 会显示成功,这正是本步骤要观察的现象。后续步骤会进行 rollback,因此评分器检查的是 revision 记录,而不是当前状态。
使用 --atomic 捕获失败
对同一错误添加 --atomic → /root/helm/05-atomic.txt
这次创建一个无法调度的 Pod:helm upgrade demo ./demo --set nodeSelector.disktype=nope --atomic --timeout 30s。因为不存在该 node label,Pod 会保持 Pending,--atomic 会捕获 timeout 并自动 rollback。命令失败才是正确结果,请将输出保存到 /root/helm/05-atomic.txt(2>&1 | tee)。
之所以使用 nodeSelector 而不是错误 image,是因为此实验的 cluster 使用 kwok,不会真正运行 Pod,却会将 Pod 标记为 Ready。因此即使 image 错误,--wait 也会通过。只有无法调度的条件才能真正阻塞。
手动回滚
helm rollback demo 2
使用 helm rollback demo 2 恢复 revision 2 的内容。helm history 中会新增一个写有 'Rollback to 2' 的 revision,并且 kubectl get deploy demo -o jsonpath='{.spec.replicas}' 应为 4。
预先查看将发生的变化
对两次 helm template 的结果执行 diff → /root/helm/07-diff.txt
养成应用前先查看差异的习惯,可以防止事故。由于没有 helm-diff plugin,请比较两次 helm template 的输出,并将结果保存到 /root/helm/07-diff.txt。结果必须存在差异。
解救卡在 pending 状态的 release
解救卡在 pending-upgrade 状态的 release
首先要真正制造卡住的状态。让无法调度的 Pod 在 --wait 中等待,再中途终止 helm process。
helm upgrade demo ./demo --set nodeSelector.disktype=nope --wait --timeout 300s &
sleep 12
kill -9 $!
实际工作中,helm process 中途终止或 CI 被取消时,就会准确进入这种状态。使用 helm list -a 检查,因为 helm list 默认会隐藏 pending。此时再次执行 helm upgrade,会被 another operation (install/upgrade/rollback) is in progress 阻止。
仅对 Secret 执行 kubectl label ... status=pending-upgrade 并不会造成卡住。helm 从 Secret 内部的 release JSON 而不是 label 读取状态;只改 label 时,helm list 仍会显示 deployed,下一次部署也会继续进行。
解救步骤:**helm 不会自行清理卡住 revision 的 Secret。**使用 kubectl get secret -l owner=helm,name=demo,status=pending-upgrade 找到它,通过 kubectl delete 删除,再对最后一个正常 revision 执行 helm rollback。完成后,helm list 必须显示 deployed,并且不能存在任何带 pending label 的 Secret。