Helm3进行template时如何处理Capabilities.KubeVersion字段
在 helm3 中有一个
Capabilities.KubeVersion
字段,可以用来标识目标 Kubernetes 集群的版本,同时在 helm 中,可以通过模板语言,使用这个值来达到兼容性处理的目标。
那么这个值,该怎么操作,才能跟随目标集群变动呢?
场景
使用到 Capabilities.KubeVersion
内置变量的场景非常简单,通过 helm create sample
即可在 sample
文件夹中,创建一个默认的 helm chart。在 templates/ingress.yaml
文件中,可以看到一段使用它的代码,如下:
1 | {{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} |
当 Capabilities.KubeVersion
发生变更时,即所部署的目标集群的版本发生变化时,会为此 Ingress 资源渲染成不同的 apiVersion
,达到兼容处理的目的。
历史变更
当前最新的版本是 3.8.2
。
在 helm 的 3.6.0 版本的 CHANGELOG 中,可以看到在 template
子命令中添加了 --kube-version
字段以及相关的测试代码。
也就是说从 3.6.0
版本之后,可以在命令行中直接通过 --kube-version
来设置 .Capabilities.KubeVersion
值。
Capabilities 是什么
它的数据结构很简单,是一个简单的结构体,只包含三个属性:
1 | // Capabilities describes the capabilities of the Kubernetes cluster. |
APIVersions 是一个字符串数组:type VersionSet []string
。
KubeVersion 包含三个值:
1 | // KubeVersion is the Kubernetes version. |
它的这三个值之间的联系,可以通过解析输入版本是的逻辑来进行区分:
1 | func ParseKubeVersion(version string) (*KubeVersion, error) { |
还可以看到 KubeVersion.String()
和 KubeVersion.GitCommit()
都是返回 KubeVersion.Version
字段:
1 | func (kv *KubeVersion) String() string { return kv.Version } |
同时可以
添加--kubeconfig
是否会自动去集群查询?
按照我们潜意识里面的认知,添加了 --kubeconfig
之后,与集群相关的数据,会以集群中的实际数据为准,也就是我们觉得它会去集群中先获得集群的版本,然后再进行渲染,但是结果却不是这样的。
通过 minikube
创建一个版本为 1.18.20
的 Kubernetes 集群:
1 | minikube start --driver=hyperkit --kubernetes-version=v1.18.20 |
这个时候,如果指定刚创建集群的 kubeconfig,Ingress 的 apiVersion 应当是 networking.k8s.io/v1beta1
,但却看到了 networking.k8s.io/v1
。
1 | helm template . --kubeconfig=/Users/yangyu/.kube/config |
也就是说指定了 kubeconfig 之后,并没有按照我们预期的那样去执行。这是为什么?
通过在 pkg/action/action.go:renderResources()
方法中的断点调试
我们可以看到,渲染时 .Capabilities.KubeVersion
的值是 v1.20.0
。
这个值不是目标集群的值,同时我们也没有指定 --kube-version
。那这个值是哪来的?通过对 KubeVersion 结构体的初始化调用的查看,可以看到有一处初始化默认版本的代码,如下:
1 | var ( |
所以,v1.20.0
这个版本是默认的 KubeVersion
。从而可以从侧面印证:即使指定了 kubeconfig,也不会从集群中获取集群的版本。
Helm template 时 Capabilities 的加载流程
总共分为3个步骤,主要看 --validate
是否为 true
。
初始化时读取 --kube-version
在 template
子命令最开始运行时,会读取 --kube-version
的输入(前提是有设置 --kube-version
)
1 | if kubeVersion != "" { |
设置默认 Capabilities 或已读取的 --kube-version
在快要进行渲染操作前,若为 ClientOnly
模式,则使用 DefaultCapabilities
或已读取的 --kube-version
。
1 | if i.ClientOnly { |
那什么是 ClientOnly
模式?在 template 命令初始化的时候,可以看到
1 | client.ClientOnly = !validate |
其中 validate
来自 f.BoolVar(&validate, "validate", false, "xxx")
。也就是说,可以通过指定 --validate=true
来避免被设置成 DefaultCapabilities
。
集群中读取 KubeVersion
如果非 ClientOnly
模式,它是从 k8s 集群中获取。代码如下:
1 | caps, err := i.cfg.getCapabilities() |
综上所述,Capablities 的初始化过程的脑图如下:
正确的姿势
经过上面的分析,正确的处理方式只有两种,如下:
1 | helm template . --kubeconfig=/Users/yangyu/.kube/config --validate=true |
或
1 | helm template . --kube-version=v1.15.0 |
所以,--kubeconfig
只是作为 --validate=true
时才会生效的一个选项。
Reference
Helm3进行template时如何处理Capabilities.KubeVersion字段