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

Helm Chart 的制作与发布

这个集群有那个 API 吗——Capabilities 与 crds

在 TT Lab 中继续学习

目标

用 .Capabilities 读取集群的版本和 API 列表来做分支,并亲自比较这些值在各个命令中来自哪里。通过安装和升级确认 crds/ 目录处于 release 之外。

为什么重要

一旦把一个 Chart 部署到多个集群,就会出现“这个集群里有没有那个 API”的问题。Helm 用 .Capabilities 把答案带进模板里,但这些值来自哪里,各命令并不相同。helm template 不看集群,使用内置默认值,而 helm install 即使是 dry-run 也会去问真实集群。于是就会有“本地不出现、部署后却出现”,反过来,只相信 CI 的渲染检查,会在生产中冒出第一次见到的对象。crds/ 在此之上又多一层——它不是模板,也不在 release 清单里,安装时先放入,升级时不动,删除 release 后仍然保留。把这五点各确认一遍,运维带 CRD 的 Chart 时,哪些事要由人来做就清楚了。

步骤

  1. 创建 /root/hc-cap/sensor Chart(名称 sensor,版本 0.1.0,values 中有 widgetSize: large),在 templates/cap.yaml 中放一个 <릴리스이름>-cap(占位符为 release 名称)ConfigMap。data 是六行——kubeVersion、major、minor(都来自 .Capabilities.KubeVersion)、helmVersion、hasIngress(networking.k8s.io/v1/Ingress 是否存在)、hasWidget(demo.labhub.io/v1/Widget 是否存在)。六个值都用引号括起来。把 helm template sense /root/hc-cap/sensor 的结果保存到 /root/hc-cap/out/offline.yaml。
  2. 把同一个 Chart 渲染成 Kubernetes 1.21.0 的样子,保存到 /root/hc-cap/out/kube121.yaml。结果中的 kubeVersion 必须是 v1.21.0,minor 必须是 21。
  3. 渲染成 demo.labhub.io/v1/Widget 存在的样子,保存到 /root/hc-cap/out/apiversions.yaml。结果中的 hasWidget 要变成 true,hasIngress 必须仍然是 false——请根据这个结果判断该选项是替换还是追加默认列表。
  4. 创建 /root/hc-cap/sensor/templates/widget.yaml。只有在 demo.labhub.io/v1/Widget 存在时,才输出 apiVersion: demo.labhub.io/v1、kind: Widget、名称 <릴리스이름>-widget(占位符为 release 名称)、spec.size 为 .Values.widgetSize 的对象。把不带选项渲染的结果保存到 /root/hc-cap/out/branch-off.yaml,把渲染成该 API 存在时的结果保存到 /root/hc-cap/out/branch-on.yaml。
  5. 在 /root/hc-cap/sensor/crds/widget.yaml 中放 widgets.demo.labhub.io CRD(组 demo.labhub.io,种类 Widget,复数形式 widgets,命名空间范围,只有一个版本 v1,spec.size 为字符串的 schema)。然后把不带选项渲染的结果保存到 /root/hc-cap/out/tpl-no-crd.yaml,把带有同时输出 CRD 的选项渲染的结果保存到 /root/hc-cap/out/tpl-with-crd.yaml。
  6. 用 helm install sense /root/hc-cap/sensor 真正安装。然后保存三样东西——release 清单保存到 /root/hc-cap/out/manifest.yaml,集群里创建出来的 CRD 保存到 /root/hc-cap/out/crd-live.yaml,已安装的 cap ConfigMap 的 data 以 JSON 保存到 /root/hc-cap/out/cap-live.json。请确认清单里有没有 CRD,有没有 Widget 对象。
  7. 在 /root/hc-cap/sensor/crds/widget.yaml 的 schema 中加上 color(字符串)字段,运行 helm upgrade sense /root/hc-cap/sensor。然后把集群里现有的 CRD 的 spec 之下的属性名用逗号连起来,保存为一行到 /root/hc-cap/out/crd-after-upgrade.txt。Chart 里有两个字段,而集群里有几个,就是这一步的答案。
  8. 把 helm template sense /root/hc-cap/sensor --validate 的结果保存到 /root/hc-cap/out/validate.yaml,把 helm install probe /root/hc-cap/sensor --dry-run=server 的结果保存到 /root/hc-cap/out/server-dryrun.yaml。并在 /root/hc-cap/out/cap-compare.json 中以布尔值写入 offline_has_widget、validate_has_widget、dryrun_has_widget 三个键。值从第 1 步和刚做好的两个文件的 hasWidget 中读取。

参考

不连集群渲染,能看到什么

创建 /root/hc-cap/sensor Chart(名称 sensor,版本 0.1.0,values 中有 widgetSize: large),在 templates/cap.yaml 中放一个 <릴리스이름>-cap(占位符为 release 名称)ConfigMap。data 是六行——kubeVersion、major、minor(都来自 .Capabilities.KubeVersion)、helmVersion、hasIngress(networking.k8s.io/v1/Ingress 是否存在)、hasWidget(demo.labhub.io/v1/Widget 是否存在)。六个值都用引号括起来。把 helm template sense /root/hc-cap/sensor 的结果保存到 /root/hc-cap/out/offline.yaml。

helm template 不会向集群查询。 它使用内置在 Helm 里的默认能力列表,所以实际存在的 Ingress 在这里也显示为没有。先亲眼确认这一事实,之后的步骤里值为什么不同就清楚了。release 名称在本实验中始终是 sense。

不连集群,假装成另一个版本来渲染

把同一个 Chart 渲染成 Kubernetes 1.21.0 的样子,保存到 /root/hc-cap/out/kube121.yaml。结果中的 kubeVersion 必须是 v1.21.0,minor 必须是 21。

helm template 有直接给出版本的选项(在 helm template --help 中找以 kube 开头的)。如果还有客户在使用旧集群,不用创建那个集群就能测试分支是否正常,这是这个选项的价值。

假装不存在的 API 存在来渲染

渲染成 demo.labhub.io/v1/Widget 存在的样子,保存到 /root/hc-cap/out/apiversions.yaml。结果中的 hasWidget 要变成 true,hasIngress 必须仍然是 false——请根据这个结果判断该选项是替换还是追加默认列表。

另有直接给出 API 列表的选项。要给多个,可以多次使用该选项,或用逗号连接。格式是 <그룹>/<버전>/<종류>(占位符依次为组、版本、种类)。这是在没有集群的情况下测试依赖由 CRD 引入的资源的 Chart 所用的办法。

根据能力加入或排除对象

创建 /root/hc-cap/sensor/templates/widget.yaml。只有在 demo.labhub.io/v1/Widget 存在时,才输出 apiVersion: demo.labhub.io/v1、kind: Widget、名称 <릴리스이름>-widget(占位符为 release 名称)、spec.size 为 .Values.widgetSize 的对象。把不带选项渲染的结果保存到 /root/hc-cap/out/branch-off.yaml,把渲染成该 API 存在时的结果保存到 /root/hc-cap/out/branch-on.yaml。

如果用 {{- ... }} 把整个 if 块包起来,条件为假时连空行都不会留下。条件为假时这个文件什么也不输出,所以渲染结果中会整个少一份文档。这是用一个 Chart 同时支持有 CRD 的集群和没有 CRD 的集群的标准方法。

crds 目录不是模板

在 /root/hc-cap/sensor/crds/widget.yaml 中放 widgets.demo.labhub.io CRD(组 demo.labhub.io,种类 Widget,复数形式 widgets,命名空间范围,只有一个版本 v1,spec.size 为字符串的 schema)。然后把不带选项渲染的结果保存到 /root/hc-cap/out/tpl-no-crd.yaml,把带有同时输出 CRD 的选项渲染的结果保存到 /root/hc-cap/out/tpl-with-crd.yaml。

crds/ 里的文件不经过模板引擎——即使写了花括号,也只是普通字符。所以默认渲染结果中也不会出现。要输出,必须另外给出选项(在 helm template --help 中找含 crds 的选项)。这个目录之所以受到特殊对待,是因为 CRD 必须先于使用它的对象放入。

放进真正的集群,能力就变了

用 helm install sense /root/hc-cap/sensor 真正安装。然后保存三样东西——release 清单保存到 /root/hc-cap/out/manifest.yaml,集群里创建出来的 CRD 保存到 /root/hc-cap/out/crd-live.yaml,已安装的 cap ConfigMap 的 data 以 JSON 保存到 /root/hc-cap/out/cap-live.json。请确认清单里有没有 CRD,有没有 Widget 对象。

helm get manifest <릴리스>(占位符为 release 名称)会输出记录在该 release 中的清单。用 kubectl get cm sense-cap -o jsonpath='{.data}' 可以把 data 以 JSON 取出。安装会向集群查询,所以 hasIngress 会与本地渲染不同。CRD 比模板先放入,所以第一次安装时 Widget 条件也会为真——请亲自确认。

修改 crds 并升级,集群仍然原封不动

在 /root/hc-cap/sensor/crds/widget.yaml 的 schema 中加上 color(字符串)字段,运行 helm upgrade sense /root/hc-cap/sensor。然后把集群里现有的 CRD 的 spec 之下的属性名用逗号连起来,保存为一行到 /root/hc-cap/out/crd-after-upgrade.txt。Chart 里有两个字段,而集群里有几个,就是这一步的答案。

Helm 只在安装时放入 crds/,升级时不动它。官方文档把这一点明确写为限制,并说明 CRD 的更新要由人用 kubectl apply 完成。属性名用 kubectl get crd <이름> -o json(占位符为 CRD 名称)取出 .spec.versions[0].schema.openAPIV3Schema.properties.spec.properties 的键即可。

同一个 Chart,三种答案——整理一下

把 helm template sense /root/hc-cap/sensor --validate 的结果保存到 /root/hc-cap/out/validate.yaml,把 helm install probe /root/hc-cap/sensor --dry-run=server 的结果保存到 /root/hc-cap/out/server-dryrun.yaml。并在 /root/hc-cap/out/cap-compare.json 中以布尔值写入 offline_has_widget、validate_has_widget、dryrun_has_widget 三个键。值从第 1 步和刚做好的两个文件的 hasWidget 中读取。

--validate 会把渲染结果发给 API 服务器验证,所以能力也从集群获取。--dry-run=server 同样如此。不看集群的只有不带选项的 helm template。必须是不带引号的 true/false——写成字符串不行。