LabHub
学习 学习路径 课程

Helm 发布与回滚

一个 release 就是一个 Secret

在 LabHub 中继续学习

一句话总结

Helm release 并不神秘,它只是命名空间里的一条 Secret。理解这一事实,就能解释回滚到底恢复什么,以及为什么有些内容无法恢复。

概念图: Secret · 卡在这里会阻止下一次部署 · 回滚不会把 revision 编号倒退。 · 新的 revision 3

为什么需要这些知识

执行 helm rollback 后,数据库迁移没有回退,导致服务损坏,这种经历很常见。相反,“回滚后什么也没变”的报障也同样常见。两者源于同一个误解——认为回滚能够让时间倒流。

Helm 所做的事情简单得多。执行 helm install 时,它会把完整的渲染后 manifest 用 gzip 压缩并保存到 Secret 中,名称为 sh.helm.release.v1.<릴리스>.v<리비전>。执行 helm upgrade 时,会再创建一个新的 revision Secret。helm rollback 3 的含义是:取出 revision 3 的 Secret,重新 apply 其中的 manifest。

因此可以得出明确规则:manifest 中声明的内容会恢复,而 manifest 之外发生的事情——迁移修改的数据、Job 创建的文件、发送给外部 API 的请求——不会恢复。

它是如何运作的

可以直接查看。

kubectl get secret -l owner=helm
kubectl get secret sh.helm.release.v1.demo.v1 -o jsonpath='{.data.release}' \
  | base64 -d | base64 -d | gzip -d | head -40

解码两次 base64 看起来奇怪,但确实正确。Kubernetes 会对 Secret 值编码一次,Helm 在内部保存时又编码一次。

helm history 就是这些 Secret 的清单。每个 revision 都有自己的状态。

状态 含义
deployed 当前正在运行的 revision,始终只有一个
superseded 曾经部署,后来让位给下一个 revision
failed apply 失败的 revision
pending-upgrade upgrade 已开始但尚未结束。卡在这里会阻止下一次部署

常见误解

回滚不会把 revision 编号倒退。 执行 helm rollback demo 1 时,不是回到 revision 1,而是用 revision 1 的内容创建新的 revision 3。查看 history,会在第 3 行看到 Rollback to 1。这样设计是为了不删除审计记录——发生过什么必须保留在历史中。

保留数量有限制。 默认值是 10 个(--history-max)。旧 revision 会被删除,所以“回滚到六个月前”通常不可能。实际可回退的时间窗口比想象中窄。

直接查看 release Secret

Helm 3 为每个 release 创建一个 Secret。理解这一结构,就能在事故中手动恢复。

kubectl -n labhub-prod get secret -l owner=helm,name=labhub
NAME                             TYPE                 DATA   AGE
sh.helm.release.v1.labhub.v247   helm.sh/release.v1   1      2d
sh.helm.release.v1.labhub.v248   helm.sh/release.v1   1      1d
sh.helm.release.v1.labhub.v249   helm.sh/release.v1   1      3h

# 안을 풀어 본다 — base64 → gzip → JSON
kubectl get secret sh.helm.release.v1.labhub.v249 -o jsonpath='{.data.release}'   | base64 -d | base64 -d | gzip -d | jq '.info, .chart.metadata.version'

陷阱在于要执行两次 base64。Kubernetes Secret 本身一层,Helm 保存时又加一层。

由此可以得出两个结论。

区分三种状态

helm list          → deployed 만 보인다
helm list --all    → failed, pending-upgrade, superseded 까지
helm history <릴리스> → 리비전별 상태와 설명

superseded 是正常状态——它表示新 revision 出现后,旧 revision 已经退位。真正的问题是 pending-*。保留在此状态时,下一次部署会被拒绝;相关进程可能早已终止,只剩状态标记仍然存在。

failed 也不能置之不理。虽然下一次部署仍可进行,但 --atomic 回滚的基准点会变得模糊。正确的收尾方式是修复原因,并完成一次成功部署。

release 名称与资源名称

Chart 中的资源名称通常由 {{ .Release.Name }}-{{ .Chart.Name }} 生成。因此,修改 release 名称会重新创建全部资源——旧资源仍然保留,新资源又被创建,二者同时存在。

基于同样原因,应从一开始谨慎确定 release 名称。如果必须修改,就要规划删除旧 release 并重新安装的步骤。对于使用 PVC 的工作负载,中间还必须加入数据迁移步骤。

生产环境中真正重要的事

release 是 Secret,也意味着它存在大小限制。etcd 的单对象上限为 1MiB。当 Chart 变大,尤其包含大量 CRD 时,release Secret 会触及这一限制,导致 upgrade 失败。届时错误消息完全不会指出真实原因,因此理解这一结构本身就决定了解决速度。