LabHub
学习 学习路径 课程

Helm 发布与回滚

钩子住在 release 外面

在 LabHub 中继续学习

一句话总结

Hook 资源不受 release 管理。 因此,回滚时它不会消失;如果没有设置删除策略,还会不断堆积在集群中。

概念图: 不受 release 管理。 · 即使回滚,Hook 已经执行的操作仍会保留。 · Job 对象会持续堆积。 · 日志会消失——通常不是好选择

为什么需要这些知识

把数据库迁移纳入部署,最常见的方式是使用 pre-upgrade Hook Job。但这个 Job 并不是 release 的一部分。Helm 会应用 Hook、等待它完成,然后再应用主要 manifest。Hook 创建的 Job 对象不会进入 release Secret。

这会产生两个结果。

它是如何运作的

metadata:
  annotations:
    "helm.sh/hook": pre-upgrade,pre-install
    "helm.sh/hook-weight": "-5"          # 작을수록 먼저
    "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded

hook-delete-policy 的三个值含义不同。

何时删除
before-hook-creation 下一次部署创建同一 Hook 之前(保留失败的 Job,便于调查)
hook-succeeded 成功后立即删除
hook-failed 失败后立即删除(日志会消失——通常不是好选择

生产环境常用的默认形式是 before-hook-creation,hook-succeeded。成功项会被清理,失败项则保留到下一次部署,以便查看日志。

常见误解

误以为 Hook 失败就会回滚。 pre-upgrade Hook 失败时,upgrade 会中断,release 会保持 failed 状态。使用 --atomic 时会触发回滚,但已经执行的迁移不会恢复。

不应放进 Hook 的工作

Hook 很方便,因此人们容易把各种工作都放进去。其中有三类不应该这样做。

耗时很长的数据迁移。 移动数百万行数据会让部署停留数十分钟。在此期间,release 会被锁定为 pending-upgrade,阻止其他部署。此类工作应与部署分离,作为独立 Job 运行,并让应用程序能够同时读取两种 schema。

通知外部系统。 使用 post-install Hook 向 Slack 发送通知很常见,但只要 Hook 失败,整个部署就会显示失败。没有必要仅因通知未发送,就把部署视为失败。这类工作应放在 CI 侧。

测试。 helm test 是独立命令,使用 helm.sh/hook: test。如果把它混进部署过程,测试稍有波动就会阻止部署。

Hook 卡住时,部署也会停止

如果 Hook Job 一直不结束,helm upgrade 就会持续等待。--timeout 默认值为 5 分钟,超过后将判定失败。但即使已经超时,Job 仍会继续在集群中运行。 Helm 只是停止等待,并不会终止 Job。

这会产生危险情况。判定失败后重新部署时,前一个迁移可能仍在运行,第二个迁移又会开始。如果同一张表上同时执行两个 ALTER,锁等待可能导致整个服务停摆。

可以通过三项措施阻止这种情况。

spec:
  activeDeadlineSeconds: 240      # helm --timeout 5m 보다 짧게
  backoffLimit: 0
  template:
    spec:
      restartPolicy: Never

Hook 与普通 manifest 的顺序

同一个 Chart 混合使用 Hook 与普通资源时,很容易混淆顺序。实际顺序如下。

pre-install 훅  →  일반 매니페스트 적용  →  post-install 훅
   (weight 순)        (Helm 의 종류별 순서)      (weight 순)

这里有一个常见陷阱:pre-install Hook 会在 Secret 和 ConfigMap 尚未存在时运行。 如果 Hook Job 引用了 release 的 Secret,就会因“没有这个 Secret”而失败。Hook 所需的值必须由 Hook 自己创建,例如在同一个 Hook 组中通过更低的 weight 创建 Secret,或者预先在 release 之外创建。

hook-weight 虽然是字符串,却按数值排序。 设置 "10""9" 时,9 会先执行。使用负数的惯例由此而来:把 -5 作为默认值,需要更早执行的项目则设为 -10

生产环境中真正重要的事

不可逆的迁移必须与部署分离。删除字段的变更应分三次部署:①添加新字段,同时保持旧代码可运行;②部署新代码;③删除旧字段。这样,无论在哪一步回滚,前后版本都能正常承受。这称为扩展—收缩(expand-contract)模式。