LabHub
学习 学习路径 课程

Helm 发布与回滚

values 按什么顺序合并

在 LabHub 中继续学习

一句话总结

-f 可以使用多次,而且后面的值会胜出--set 的优先级又高于所有 -f。不了解这个顺序,就可能为“明明设置了值,为什么没有生效”白白耗上一整天。

概念图: 后面的值会胜出 · 从低到高 · 映射会合并,但数组会被整体替换。 · --set 中的逗号与点。

为什么需要理解优先级

生产部署中的 values 文件通常有两三层:Chart 默认值、各环境的值,以及 CI 注入的镜像标签。如果混淆了谁会覆盖谁,预发布环境的值就可能泄漏到生产环境。

优先级按从低到高排列如下。

  1. Chart 中的 values.yaml
  2. 父 Chart 传给子 Chart 的值
  3. -f a.yaml(先出现)
  4. -f b.yaml(后出现——覆盖 a)
  5. --set / --set-string / --set-file

它是如何工作的

不要猜测合并结果,应该直接进行确认。

helm template demo ./chart -f prod.yaml --set image.tag=abc123 \
  --show-only templates/deployment.yaml

helm get values demo            # 배포된 릴리스에 실제로 들어간 값
helm get values demo --all      # 기본값까지 합친 전체

事故调查时,helm get values 是最先执行的命令。它是回答“当时究竟用了哪些值启动”的唯一事实来源。

常见误解

映射会合并,但数组会被整体替换。 如果两个 -f 文件中各自包含列表,它们不会合并,而是由后一个完整覆盖前一个。因此,把 extraEnv 之类的列表拆到不同环境文件中,最终只会剩下一份。如果确实需要合并列表,标准做法是把数据结构设计成映射。

--set 中的逗号与点。 --set a.b=1,a.c=2 表示两个值。如果值本身包含逗号,就必须使用 \, 转义。忽略这一点而截断镜像标签,是一种常见事故。值比较复杂时,使用 --set-string 或临时 values 文件更加安全。

锁定依赖才能保证可复现

Chart.yamldependencies 中填写的版本是一个范围

dependencies:
  - name: postgresql
    version: "15.x.x"        # 15.5.0 도, 15.9.2 도 이 범위다
    repository: https://charts.bitnami.com/bitnami

每次运行 helm dependency update 时,都可能选中不同版本。解析结果会写入 Chart.lock,而且必须把这个文件提交到仓库,其他人和 CI 才能获取同样的 内容。如果把它放进 .gitignore,“明明在我的电脑上可以运行”的问题就会开始出现。

helm dependency build     # Chart.lock 대로 받는다 (재현된다)
helm dependency update    # 범위를 다시 풀어 lock 을 갱신한다 (의도할 때만)

CI 中应使用 build。如果使用 update,每次部署都可能获取到不同的依赖版本。

通过条件与标签启用或禁用

有时需要根据环境排除某个子 Chart。例如,开发环境使用 Chart 附带的 PostgreSQL, 而生产环境使用托管数据库。

# Chart.yaml
dependencies:
  - name: postgresql
    version: 15.5.0
    repository: https://charts.bitnami.com/bitnami
    condition: postgresql.enabled     # 이 값이 false 면 통째로 빠진다
# values/prod.yaml
postgresql:
  enabled: false
externalDatabase:
  host: labhub-db-prod-rw.labhub-prod.svc

condition 根据单个值进行判断,而 tags 可以用一个开关控制多个子 Chart。 条件为假时,该子 Chart 根本不会渲染,因此即使其中的值有误,部署也可能通过—— 直到重新启用它时,问题才会首次暴露。

分三步查明值为什么没有生效

# 1) 최종 값이 무엇인가 — 여기서 대개 끝난다
helm template demo ./chart -f prod.yaml --set image.tag=abc | grep -A2 image:

# 2) 값은 맞는데 템플릿이 안 쓰는가
helm template demo ./chart --debug 2>&1 | head -40      # 렌더 전 값이 보인다

# 3) 배포된 릴리스에 실제로 들어간 값
helm get values demo --all

第二步经常发现的原因是拼写错误。即使把 imagePullSecrets 写成 imagePullSecret, Helm 也不会报错——这个值只会静静地不被使用。 因此,在 Chart 中提供 values.schema.json,就能在部署前发现未知键。

实际工作中真正重要的事

子 Chart 的值必须在父 Chart 中以子 Chart 名称作为键来指定。

# 부모 차트의 values.yaml
postgresql:
  auth:
    database: labhub

只有放在 global: 下的值,才能由所有子 Chart 共同读取。不了解这个区别,就会一直困惑于“为什么子 Chart 没有读取这个值”。