TT Lab
开始
学习 学习路径 课程

Helm Chart 的制作与发布

我手工改的字段在升级后消失了

在 TT Lab 中继续学习

目标

亲手制造并确认,在集群里手动修改过的值和标签,在 helm upgrade 之后会怎样;并通过 release 记录比较沿用之前用户值的三个选项的差别。

为什么重要

Helm 3 在升级时用旧清单、新清单、集群实物这三者制作补丁。这一条规则就能解释现场反复出现的两种现象——故障期间用 kubectl scale 调高的副本数会在下次部署时被改回去,而紧急加上的标签会原样保留。因为 Chart 声明了的字段,以声明为准;Chart 不知道的字段,则不去碰。此外在值这一侧还有一条规则。helm upgrade 默认不会沿用上一个 release 的用户值。所以部署脚本里一旦漏掉一个 --set,那个值就会悄悄回到 Chart 默认值。--reuse-values 解决了这个问题,却让值只留在 release 里,在仓库中看不见。用哪一个,不该凭喜好,而应由“部署能否重现”来决定,而要做到这一点,就得亲眼看一次这三个选项实际做了什么。

步骤

  1. 创建 /root/hc-upgrade/ledger Chart(名称 ledger,版本 0.1.0)。values.yaml 有 replicas: 1、image: "registry.local/ledger:1.0.0"、extraLabel: "" 三个值。templates/deployment.yaml 是名称为 <릴리스이름>-ledger(占位符为 release 名称)的 Deployment,在 metadata.labels 中放 app: ledger,只有 extraLabel 不为空时才加上 tier: <그 값>(占位符为该值)。以 release 名称 books 安装之后,把 helm get manifest books 保存到 /root/hc-upgrade/out/rev1-manifest.yaml。
  2. 用 kubectl 把 books-ledger Deployment 的副本数调到 5,并加上标签 owner=ops。把那个状态以 {"replicas": …, "owner": …, "tier": …} 三个键的 JSON 保存到 /root/hc-upgrade/out/before-upgrade.json(没有的标签写 null)。
  3. 在完全不改 Chart 和值的情况下运行 helm upgrade books /root/hc-upgrade/ledger。然后把同样三个键的 JSON 保存到 /root/hc-upgrade/out/after-upgrade.json,确认手动修改的两项中,哪个保留了、哪个被改回去了。
  4. 用 --set extraLabel=gold 升级,把带有 tier 标签的状态保存到 /root/hc-upgrade/out/label-added.json。接着把 extraLabel 设为空字符串再次升级,把 tier 标签消失后的状态保存到 /root/hc-upgrade/out/label-removed.json。两个文件都是同样三个键的 JSON。这时也请一并看看 owner 标签会怎样。
  5. 用 --set replicas=4 --set extraLabel=silver 升级,把 helm get values books -o json 保存到 /root/hc-upgrade/out/values-1.json。接着只给出 --set replicas=6 再次升级,把同一命令的结果保存到 /root/hc-upgrade/out/values-2.json。extraLabel 会怎样,就是答案。
  6. 沿用上一个 release 的用户值,只加上 --set extraLabel=bronze 来升级。把 helm get values books -o json 的结果保存到 /root/hc-upgrade/out/values-reuse.json。replicas 必须保留上一步的 6,extraLabel 必须是 bronze。
  7. 先用 --set replicas=4 --set extraLabel=silver 升级,建立基准。在此基础上,对 --set replicas=7 加上先回到 Chart 默认值、再叠加上次用户值的选项升级,把结果保存到 /root/hc-upgrade/out/values-rtr.json。接着对 --set replicas=9 加上丢弃上次的值的选项升级,把结果保存到 /root/hc-upgrade/out/values-reset.json。
  8. 用 --set replicas=3 运行服务端预览,把输出保存到 /root/hc-upgrade/out/dryrun.yaml(release 不能改变)。然后用同样的值加上 --force 真正升级,把之后的状态以与第 2 步相同的三个键的 JSON 保存到 /root/hc-upgrade/out/after-force.json——请确认手动加上的 owner 标签会怎样。把 helm history books -o json 保存到 /root/hc-upgrade/out/history.json,并在 /root/hc-upgrade/out/merge-report.json 中写入 manual_scale_kept、manual_label_kept、chart_removed_label_deleted、default_upgrade_reuses_values、manual_label_survives_force 五个布尔值和 final_replicas 数字。值从前面步骤保存的文件中读取。

参考

先部署一个之后要改回去看的东西

创建 /root/hc-upgrade/ledger Chart(名称 ledger,版本 0.1.0)。values.yaml 有 replicas: 1、image: "registry.local/ledger:1.0.0"、extraLabel: "" 三个值。templates/deployment.yaml 是名称为 <릴리스이름>-ledger(占位符为 release 名称)的 Deployment,在 metadata.labels 中放 app: ledger,只有 extraLabel 不为空时才加上 tier: <그 값>(占位符为该值)。以 release 名称 books 安装之后,把 helm get manifest books 保存到 /root/hc-upgrade/out/rev1-manifest.yaml。

在 kwok 集群里 Pod 不会真的运行,但 Deployment 对象会正常创建——本实验只看对象的字段值。有条件地加标签的部分,用 {{- if .Values.extraLabel }} 块包起来,并用前面的 - 让条件为假时不留空行。

在集群里手动修改

用 kubectl 把 books-ledger Deployment 的副本数调到 5,并加上标签 owner=ops。把那个状态以 {"replicas": …, "owner": …, "tier": …} 三个键的 JSON 保存到 /root/hc-upgrade/out/before-upgrade.json(没有的标签写 null)。

是 kubectl scale deploy/books-ledger --replicas=5 和 kubectl label deploy/books-ledger owner=ops --overwrite 两条命令。这是故障应对中常做的事,问题出在下一次部署。取出 JSON 时用 kubectl get deploy books-ledger -o json | jq '{...}'。

一点不改 Chart 就升级

在完全不改 Chart 和值的情况下运行 helm upgrade books /root/hc-upgrade/ledger。然后把同样三个键的 JSON 保存到 /root/hc-upgrade/out/after-upgrade.json,确认手动修改的两项中,哪个保留了、哪个被改回去了。

Helm 3 用旧清单、新清单、集群实物这三者制作补丁。Chart 声明了值的字段,即使集群实物不同,也会按声明一侧对齐。Chart 根本不知道的字段则不去碰。必须能用这两条规则解释结果。

从 Chart 中去掉的字段,在集群里也会被删掉

用 --set extraLabel=gold 升级,把带有 tier 标签的状态保存到 /root/hc-upgrade/out/label-added.json。接着把 extraLabel 设为空字符串再次升级,把 tier 标签消失后的状态保存到 /root/hc-upgrade/out/label-removed.json。两个文件都是同样三个键的 JSON。这时也请一并看看 owner 标签会怎样。

条件变为假,新清单里就没有那个标签了。Helm 会与旧清单对比,生成删除缺失字段的补丁。而 owner 是哪个清单里都没有过的字段,所以不属于补丁对象。由 Chart 管理的与由人加上的,界线就在这里分开。注意:如果升级时一个值也不给,Helm 会原样使用上一个 release 的用户值——所以仅仅去掉 --set,gold 并不会消失。请亲自试一下,确认差别。

升级会丢弃上次的用户值

用 --set replicas=4 --set extraLabel=silver 升级,把 helm get values books -o json 保存到 /root/hc-upgrade/out/values-1.json。接着只给出 --set replicas=6 再次升级,把同一命令的结果保存到 /root/hc-upgrade/out/values-2.json。extraLabel 会怎样,就是答案。

helm get values 只显示用户给出的值(想连 Chart 默认值也看,用 --all)。在默认行为下,升级不会沿用上一个 release 的用户值,只使用这次给出的。部署脚本每次都得把所有 --set 重新写一遍,原因就在这里。

沿用上次的值,只改一个值

沿用上一个 release 的用户值,只加上 --set extraLabel=bronze 来升级。把 helm get values books -o json 的结果保存到 /root/hc-upgrade/out/values-reuse.json。replicas 必须保留上一步的 6,extraLabel 必须是 bronze。

有专门的沿用选项(在 helm upgrade --help 中找含 reuse 的)。看起来方便,但有个陷阱——沿用来的值既不在命令行,也不在仓库,只在 release 里。所以 release 越久,就越没有人知道“现在是用什么值在运行”。

把三个沿用选项并排放在一起

先用 --set replicas=4 --set extraLabel=silver 升级,建立基准。在此基础上,对 --set replicas=7 加上先回到 Chart 默认值、再叠加上次用户值的选项升级,把结果保存到 /root/hc-upgrade/out/values-rtr.json。接着对 --set replicas=9 加上丢弃上次的值的选项升级,把结果保存到 /root/hc-upgrade/out/values-reset.json。

三个选项的名字彼此相似,容易混淆——请在 helm upgrade --help 中把这三个并排读一遍。一个是原样沿用上次的值,一个是先回到默认值再叠加上次的用户值,一个是把上次的值彻底丢掉。可以通过保存下来的两个文件中键的个数差异来区分。

预览、用替换来应用,并整理规则

用 --set replicas=3 运行服务端预览,把输出保存到 /root/hc-upgrade/out/dryrun.yaml(release 不能改变)。然后用同样的值加上 --force 真正升级,把之后的状态以与第 2 步相同的三个键的 JSON 保存到 /root/hc-upgrade/out/after-force.json——请确认手动加上的 owner 标签会怎样。把 helm history books -o json 保存到 /root/hc-upgrade/out/history.json,并在 /root/hc-upgrade/out/merge-report.json 中写入 manual_scale_kept、manual_label_kept、chart_removed_label_deleted、default_upgrade_reuses_values、manual_label_survives_force 五个布尔值和 final_replicas 数字。值从前面步骤保存的文件中读取。

--dry-run=server 会发送到 API 服务器只做验证,不创建 release。--force 以替换方式而不是补丁来应用——在有无法用补丁修改的不可变字段时使用,但因为是替换,对象会被整个换成新清单。那么第 3 步中保留下来的东西,这次会怎样?请先想一想再确认。五个布尔值,对照第 2–5 步和刚保存的 JSON 就能得出。