Helm Chart 如何兼容不同的 Kubernetes 版本
隨著 Kubernetes 的版本不斷迭代發(fā)布,很多 Helm Chart 包壓根跟不上更新的進度,導致在使用較新版本的 Kubernetes 的時候很多 Helm Chart 包不兼容,所以我們在開發(fā) Helm Chart 包的時候有必要考慮到對不同版本的 Kubernetes 進行兼容。
要實現(xiàn)對不同版本的兼容核心就是利用 Helm Chart 模板提供的內(nèi)置對象 Capabilities,該對象提供了關(guān)于 Kubernetes 集群支持功能的信息,包括如下特性:
Capabilities.APIVersions獲取集群版本集合Capabilities.APIVersions.Has $version判斷集群中的某個版本 (e.g., batch/v1) 或是資源 (e.g., apps/v1/Deployment) 是否可用Capabilities.KubeVersion和Capabilities.KubeVersion.Version可以獲取 Kubernetes 版本號Capabilities.KubeVersion.Major獲取 Kubernetes 的主版本Capabilities.KubeVersion.Minor獲取 Kubernetes 的次版本Capabilities.HelmVersion包含 Helm 版本詳細信息的對象,和helm version的輸出一致Capabilities.HelmVersion.Version是當前 Helm 版本的語義格式Capabilities.HelmVersion.GitCommitHelm 的git sha1值Capabilities.HelmVersion.GitTreeState是 Helm git 樹的狀態(tài)Capabilities.HelmVersion.GoVersion使用的 Go 編譯器版本
利用上面的幾個對象我們可以判斷資源對象需要使用的 API 版本或者屬性,下面我們以 Ingress 資源對象為例進行說明。
Kubernetes 在 1.19 版本為 Ingress 資源引入了一個新的 API:networking.k8s.io/v1,這與之前的 networking.k8s.io/v1beta1 beta 版本使用方式基本一致,但是和前面的 extensions/v1beta1 這個版本在使用上有很大的不同,資源對象的屬性上有一定的區(qū)別,所以要兼容不同的版本,我們就需要對模板中的 Ingress 對象做兼容處理。
新版本的資源對象格式如下所示:
apiVersion:?networking.k8s.io/v1
kind:?Ingress
metadata:
??name:?minimal-ingress
??annotations:
????nginx.ingress.kubernetes.io/rewrite-target:?/
spec:
??rules:
??-?http:
??????paths:
??????-?path:?/testpath
????????pathType:?Prefix
????????backend:
??????????service:
????????????name:?test
????????????port:
??????????????number:?80
而舊版本的資源對象格式如下:
apiVersion:?extensions/v1beta1
kind:?Ingress
metadata:
??name:?minimal-ingress
??annotations:
????nginx.ingress.kubernetes.io/rewrite-target:?/
spec:
??rules:
??-?http:
??????paths:
??????-?path:?/testpath
????????backend:
??????????serviceName:?test
??????????servicePort:?80
具體使用哪種格式的資源對象需要依賴我們的集群版本,首先我們在 Chart 包的 _helpers.tpl 文件中添加幾個用于判斷集群版本或 API 的命名模板:
{{/*?Allow?KubeVersion?to?be?overridden.?*/}}
{{-?define?"ydzs.kubeVersion"?-}}
??{{-?default?.Capabilities.KubeVersion.Version?.Values.kubeVersionOverride?-}}
{{-?end?-
{{/*?Get?Ingress?API?Version?*/}}
{{-?define?"ydzs.ingress.apiVersion"?-}}
??{{-?if?and?(.Capabilities.APIVersions.Has?"networking.k8s.io/v1")?(semverCompare?">=?1.19-0"?(include?"ydzs.kubeVersion"?.))?-}}
??????{{-?print?"networking.k8s.io/v1"?-}}
??{{-?else?if?.Capabilities.APIVersions.Has?"networking.k8s.io/v1beta1"?-}}
????{{-?print?"networking.k8s.io/v1beta1"?-}}
??{{-?else?-}}
????{{-?print?"extensions/v1beta1"?-}}
??{{-?end?-}}
{{-?end?-}}
{{/*?Check?Ingress?stability?*/}}
{{-?define?"ydzs.ingress.isStable"?-}}
??{{-?eq?(include?"ydzs.ingress.apiVersion"?.)?"networking.k8s.io/v1"?-}}
{{-?end?-}}
{{/*?Check?Ingress?supports?pathType?*/}}
{{/*?pathType?was?added?to?networking.k8s.io/v1beta1?in?Kubernetes?1.18?*/}}
{{-?define?"ydzs.ingress.supportsPathType"?-}}
??{{-?or?(eq?(include?"ydzs.ingress.isStable"?.)?"true")?(and?(eq?(include?"ydzs.ingress.apiVersion"?.)?"networking.k8s.io/v1beta1")?(semverCompare?">=?1.18-0"?(include?"ydzs.kubeVersion"?.)))?-}}
{{-?end?-}}
上面我們通過 .Capabilities.APIVersions.Has 來判斷我們應(yīng)該使用的 APIVersion,如果版本為 networking.k8s.io/v1,則定義為 isStable,此外還根據(jù)版本來判斷是否需要支持 pathType 屬性,然后在 Ingress 對象模板中就可以使用上面定義的命名模板來決定應(yīng)該使用哪些屬性,如下 ingress.yaml 文件所示:
{{-?$apiIsStable?:=?eq?(include?"ydzs.ingress.isStable"?.)?"true"?-}}
{{-?$ingressSupportsPathType?:=?eq?(include?"ydzs.ingress.supportsPathType"?.)?"true"?-}}
{{-?$ingressClass?:=?index?.Values?"ingress-nginx"?"controller"?"ingressClass"?}}
apiVersion:?{{?include?"ydzs.ingress.apiVersion"?.?}}
kind:?Ingress
metadata:
??name:?portal-ingress
??annotations:
????{{-?if?$ingressClass?}}
????kubernetes.io/ingress.class:?{{?$ingressClass?}}
????{{-?end?}}
????nginx.ingress.kubernetes.io/proxy-connect-timeout:?"120"
????nginx.ingress.kubernetes.io/proxy-read-timeout:?"3600"
????nginx.ingress.kubernetes.io/proxy-send-timeout:?"3600"
????nginx.ingress.kubernetes.io/ssl-redirect:?"false"
??labels:
????{{-?include?"ydzs.labels"?.?|?nindent?4?}}
spec:
??rules:
??{{-?if?eq?.Values.endpoint.type?"FQDN"?}}
??-?host:?{{?required?".Values.endpoint.FQDN?is?required?for?FQDN"?.Values.endpoint.FQDN?}}
????http:
??{{-?else?}}
??-?http:
??{{-?end?}}
??????paths:
??????-?path:?/
????????{{-?if?$ingressSupportsPathType?}}
????????pathType:?Prefix
????????{{-?end?}}
????????backend:
??????????{{-?if?$apiIsStable?}}
??????????service:
????????????name:?portal
????????????port:
??????????????number:?80
??????????{{-?else?}}
??????????serviceName:?portal
??????????servicePort:?80
??????????{{-?end?}}
在 Ingress 模板中使用命名模板中的變量來判斷應(yīng)該使用哪些屬性,這樣我們定義的這個 Chart 模板就可以兼容 Kubernetes 的不同版本了,如果還有其他版本之間的差異,我們也可以分別判斷進行定義即可,對于其他的資源對象,比如 Deployment 也可以用同樣的方式進行兼容。
