Helm Helm

生命周期 Hook 与 Chart 测试

在安装或升级前后运行一次性工作,并编写一个验证 release 确实可用的测试。

12 min 高级

chart 所做的大部分事情,都是声明会持续运行的资源。有时你需要某个东西在特定时刻运行一次,比如升级之前的数据库迁移、卸载之后的清理作业,或者在 release 启动后检查它确实可用。Helm 通过 hook 和 chart 测试来覆盖这两种情况。

什么是 hook

hook 是一个普通的 Kubernetes 资源,最常见的是 Job,通过注解告诉 Helm 它应当在一次 install、upgrade、rollback 或 uninstall 的哪个时间点运行:

# templates/hooks/pre-install-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: {{ .Values.appName }}-pre-install
  annotations:
    "helm.sh/hook": pre-install
    "helm.sh/hook-weight": "0"
    "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
spec:
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: migrate
          image: myorg/webapp-migrate:1.0
          command: ["./run-migrations.sh"]

helm.sh/hook 注解使它成为一个 hook,而不是 Helm 作为 release 一部分跟踪的普通资源。常见的 hook 点有 pre-install、post-install、pre-upgrade、post-upgrade、pre-rollback、post-rollback、pre-delete 和 post-delete;完整的列表(包括几个与测试相关的)见 Helm hooks 文档。

Helm 如何为 hook 排序

对于 pre-install hook:

  1. Helm 渲染 hook 资源并在集群中创建它,先于 chart 中的其他任何东西。
  2. Helm 等待它达到就绪或完成状态(运行到完成的 Job 算数)。
  3. 只有那时,Helm 才渲染并应用 chart 的其余资源。

post-install 则颠倒第 1 步和第 3 步:chart 的常规资源先进入,然后 hook 运行。失败的 pre-upgrade hook 会中止升级,这正是把迁移放在这里运行、而不是指望它事后成功的意义所在。

Hook 权重与删除策略

helm.sh/hook-weight 在同一时间点对多个 hook 排序,数字越小越先运行,以普通字符串形式书写("0"、"5"),没有权重的 hook 默认为 0。helm.sh/hook-delete-policy 控制清理,因为已完成的 Job 否则会无限期地留在集群中:

  • before-hook-creation(默认):在创建新的 hook 资源之前删除先前的那个,这样重试不会与同名的遗留 Job 冲突。
  • hook-succeeded:成功完成后删除该资源。
  • hook-failed:失败时删除它,当你宁愿清理也不愿保留一个失败的 Job 以供检查时很有用;如果你想在失败的 Job 被移除之前用 kubectl logs 查看,则省略它。

例如,pre-install,hook-succeeded 的组合意味着 hook 运行一次,成功,然后自行清理,除了你的 Job 自己的输出之外不留痕迹;如果你也不想让失败的尝试留在那里,还可以加上 hook-failed。

试一试

kubectl get jobs -w

在另一个终端中:

helm install web ./webapp

观察第一个终端,你应该会看到 hook Job 出现、运行、完成,并(取决于它的删除策略)消失,这一切都发生在 chart 的 Deployment 出现之前。这是真正看到排序过程、而不是照单全收的最简单方式。

Chart 测试:在 release 运行之后验证它

chart 测试是在 release 存在之后按需运行的 Job,用来检查它确实可用:

# templates/tests/test-connection.yaml
apiVersion: v1
kind: Pod
metadata:
  name: "{{ .Values.appName }}-test-connection"
  annotations:
    "helm.sh/hook": test
spec:
  containers:
    - name: wget
      image: busybox:1.36
      command: ["wget", "-qO-", "{{ .Values.appName }}"]
  restartPolicy: Never
helm install web ./webapp
helm test web

helm test 会运行 release 中所有带有 helm.sh/hook: test 注解的资源,并根据每个 Pod 的退出状态报告通过或失败;得到响应的 wget 以 0 退出,无法连接的则不会。与 install/upgrade hook 不同,测试资源默认不会被自动删除,运行 helm test --logs 可以内联查看它们的输出,或者在两次运行之间自行清理它们。

何时选用哪一个

  • 当某件事需要在 release 生命周期的特定时间点恰好发生一次,并且部署的其余部分应当等待它或对它做出反应时,使用 hook:升级之前的 schema 迁移、安装之后通知外部系统、卸载之前清理外部资源。
  • 对于任何你想针对一个已在运行的 release 按需重新运行的内容,使用 chart 测试,最常见的是在 CI 流水线中,于 helm install 或 helm upgrade 之后作为冒烟测试,而不是作为部署序列本身的一部分。

在注解之下,两者都是普通的 Kubernetes 资源,所以你已经知道的有关调试 Job 或 Pod 的一切,kubectl describe、kubectl logs,都可以直接适用。

热门指南