LabHub
学习 学习路径 课程

Helm 发布与回滚

部署、弄坏、再回滚

在 LabHub 中继续学习

目标

让部署变得可以回滚。完成一整轮操作:部署、故意破坏、用两种方式恢复,以及解救卡住的 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

步骤

  1. helm create demohelm install
  2. 从 release Secret 中提取 manifest,保存到 /root/helm/02-manifest.yaml
  3. 使用 --set replicaCount=4 创建 revision 2
  4. 使用不存在的 image 执行 upgrade,确认它仍显示成功
  5. 对同一错误添加 --atomic/root/helm/05-atomic.txt
  6. helm rollback demo 2
  7. 对两次 helm template 的结果执行 diff → /root/helm/07-diff.txt
  8. 解救卡在 pending-upgrade 状态的 release

参考

创建并部署 chart

helm create demohelm 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 -dbase64 -dgzip -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。