一个 release 就是一个 Secret
一句话总结
Helm release 并不神秘,它只是命名空间里的一条 Secret。理解这一事实,就能解释回滚到底恢复什么,以及为什么有些内容无法恢复。
为什么需要这些知识
执行 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 保存时又加一层。
由此可以得出两个结论。
- release 历史会占用命名空间中的 Secret。 如果不设置
--history-max,默认会积累 10 个;Chart 较大时,每个都可能达到数百 KB。 - 删除命名空间也会删除 release。 它不应作为需要备份的对象,而应确保可以重建。因此,把 values 文件和 Chart 版本保存在 git 中,才是真正的备份。
区分三种状态
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 失败。届时错误消息完全不会指出真实原因,因此理解这一结构本身就决定了解决速度。