DevOps CI/CD 管道在 Kubernetes 升级到 v1.22 后中断
DevOps CI/CD pipelines broken after Kubernetes upgrade to v1.22
现状
在 v1.22 中,Kubernetes 放弃了对 v1beta1
API 的支持。这导致我们的发布管道崩溃,我们不确定如何修复它。
我们使用构建管道来构建 .NET Core 应用程序并将它们部署到 Azure 容器注册表。然后是使用 helm
从该 ACR 在集群中升级它们的发布管道。这就是它的样子。
构建管道:
- .NET 下载、恢复、构建、测试、发布
- Docker 任务 v0:构建任务
- Docker 任务 v0:推送到
ACR
任务
- 工件发布到 Azure Pipelines
发布渠道:
- Helm 工具安装程序:安装
helm
v3.2.4(检查最新版本的 Helm 未选中)并安装最新的 Kubectl
(检查最新版本)
- Bash 任务:
az acr login --name <acrname>
az acr helm repo add --name <acrname>
- 头盔升级任务:
- 图表名称
<acrname>/<chartname>
- 版本
empty
- 发布名称`
升级到 Kubernetes v1.22 后,我们在发布步骤 3 中收到以下错误:
Error: UPGRADE FAILED: unable to recognize "": no matches for kind "Ingress" in version "extensions/v1beta1"
.
我已经尝试过的
错误非常明显,Helm compatibility table 清楚地指出我需要升级发布管道以至少使用 Helm v3.7.x。不幸的是,在此版本中,OCI 功能(稍后会介绍)仍处于实验阶段,因此至少必须使用 v3.8.x。
将 helm 版本升级到 v3.8.0
这使得发布步骤 3。报告:
Error: looks like "https://<acrname>.azurecr.io/helm/v1/repo" is not a valid chart repository or cannot be reached: error unmarshaling JSON: while decoding JSON: json: unknown field "acrMetadata"
阅读有关 how to live with helm
and ACR
的 Microsoft 教程后,我了解到 az acr helm
命令使用 helm v2,因此已弃用,应使用 OCI
工件。
切换到 OCI 第 1 部分
阅读后我将发布步骤 2. 更改为单行:
helm registry login <acrname>.azurecr.io --username <username> --password <password>
现在在发布步骤 2 中给了我 Login Succeeded
。但是发布步骤 3。失败并显示
Error: failed to download "<acrname>/<reponame>"
.
切换到 OCI 第 2 部分
我认为 helm 任务不兼容或与新方法不兼容,所以我删除了发布步骤 3。并决定在步骤 2 中从命令行进行。所以现在步骤 2 看起来像这样:
helm registry login <acrname>.azurecr.io --username <username> --password <password>
helm upgrade --install --wait -n <namespace> <deploymentName> oci://<acrname>.azurecr.io/<reponame> --version latest --values ./values.yaml
不幸的是,这仍然给我:
Error: failed to download "oci://<acrname>.azurecr.io/<reponame>" at version "latest"
Helm 拉取、导出、升级而不只是升级
接下来的尝试是将 help upgrade
拆分为 helm pull
、helm export
和 helm upgrade
,但
helm pull oci://<acrname>.azurecr.io/<reponame> --version latest
给我:
Error: manifest does not contain minimum number of descriptors (2), descriptors found: 0
将 docker build
和 docker push
任务更改为 v2
我还尝试将构建管道中的 docker 任务更改为 v2。但这根本没有改变任何东西。
您是否尝试过将 Ingress 对象的 apiVersion
更改为 networking.k8s.io/v1beta1
或 networking.k8s.io/v1
? Support for Ingress in the extensions/v1beta1 API version is dropped in k8s 1.22.
我们的 helm chart 中的 ingress.yaml
文件看起来像这样支持多个 k8s 版本。您可以忽略 AWS-specific 注释,因为您使用的是 Azure。我们的图表具有 ingress.enablePathType
的全局值,因为在编写 yaml 文件时,AWS Load Balancer did not support pathType 因此我们将该值设置为 false。
{{- if .Values.global.ingress.enabled -}}
{{- $useV1Ingress := and (.Capabilities.APIVersions.Has "networking.k8s.io/v1/Ingress") .Values.global.ingress.enablePathType -}}
{{- if $useV1Ingress -}}
apiVersion: networking.k8s.io/v1
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
{{- end }}
kind: Ingress
metadata:
name: example-ingress
labels:
{{- include "my-chart.labels" . | nindent 4 }}
annotations:
{{- if .Values.global.ingress.group.enabled }}
alb.ingress.kubernetes.io/group.name: {{ required "ingress.group.name is required when ingress.group.enabled is true" .Values.global.ingress.group.name }}
{{- end }}
{{- with .Values.global.ingress.annotations }}
{{- toYaml . | nindent 4 }}
{{- end }}
# Add these tags to the AWS Application Load Balancer
alb.ingress.kubernetes.io/tags: k8s.namespace/{{ .Release.Namespace }}={{ .Release.Namespace }}
spec:
rules:
- host: {{ include "my-chart.applicationOneServerUrl" . | quote }}
http:
paths:
{{- if $useV1Ingress }}
- path: /
pathType: Prefix
backend:
service:
name: {{ $applicationOneServiceName }}
port:
name: http-grails
{{- else }}
- path: /*
backend:
serviceName: {{ $applicationOneServiceName }}
servicePort: http-grails
{{- end }}
- host: {{ include "my-chart.applicationTwoServerUrl" . | quote }}
http:
paths:
{{- if $useV1Ingress }}
- path: /
pathType: Prefix
backend:
service:
name: {{ .Values.global.applicationTwo.serviceName }}
port:
name: http-grails
{{- else }}
- path: /*
backend:
serviceName: {{ .Values.global.applicationTwo.serviceName }}
servicePort: http-grails
{{- end }}
{{- end }}
只是为了使图片完整 - @wubbalubba 提到图表定义中入口的 YAML 的变化并不是我修复我们的管道必须做的唯一事情:
- 所以首先,很明显,将 ingress 的 YAML 文件中图表定义内的 API 更改为
v1
,并增加图表版本。然后重新打包推送到ACR:
helm package .
helm push .\generated-new-chart.tgz oci://<acrname>.azurecr.io/
- 从 this guide 中学到的下一件事是更新,或者更确切地说,我只是删除了与我的服务相关的所有机密和配置映射:
kubectl delete secret -l owner=helm,status=deployed,name=<release_name> --namespace <release_namespace>
kubectl delete configmap -l owner=helm,status=deployed,name=<release_name> --namespace <release_namespace>
- 最后,删除部署 helm 升级步骤。相反 shell 脚本承担了责任:
helm registry login $(ContainerRegistryUrl) --username $(ContainerRegistryUsername) --password $(ContainerRegistryPassword)
az aks get-credentials --resource-group $(Kubernetes__ResourceGroup) --name $(Kubernetes__Cluster)
helm upgrade --install --wait -n $(NamespaceName) $(ServiceName) oci://$(ContainerRegistryUrl)/services-generic-chart --version 2 -f ./values.yaml
直到那时我才能够成功地重新部署所有内容。
现状
在 v1.22 中,Kubernetes 放弃了对 v1beta1
API 的支持。这导致我们的发布管道崩溃,我们不确定如何修复它。
我们使用构建管道来构建 .NET Core 应用程序并将它们部署到 Azure 容器注册表。然后是使用 helm
从该 ACR 在集群中升级它们的发布管道。这就是它的样子。
构建管道:
- .NET 下载、恢复、构建、测试、发布
- Docker 任务 v0:构建任务
- Docker 任务 v0:推送到
ACR
任务 - 工件发布到 Azure Pipelines
发布渠道:
- Helm 工具安装程序:安装
helm
v3.2.4(检查最新版本的 Helm 未选中)并安装最新的Kubectl
(检查最新版本) - Bash 任务:
az acr login --name <acrname>
az acr helm repo add --name <acrname>
- 头盔升级任务:
- 图表名称
<acrname>/<chartname>
- 版本
empty
- 发布名称`
- 图表名称
升级到 Kubernetes v1.22 后,我们在发布步骤 3 中收到以下错误:
Error: UPGRADE FAILED: unable to recognize "": no matches for kind "Ingress" in version "extensions/v1beta1"
.
我已经尝试过的
错误非常明显,Helm compatibility table 清楚地指出我需要升级发布管道以至少使用 Helm v3.7.x。不幸的是,在此版本中,OCI 功能(稍后会介绍)仍处于实验阶段,因此至少必须使用 v3.8.x。
将 helm 版本升级到 v3.8.0
这使得发布步骤 3。报告:
Error: looks like "https://<acrname>.azurecr.io/helm/v1/repo" is not a valid chart repository or cannot be reached: error unmarshaling JSON: while decoding JSON: json: unknown field "acrMetadata"
阅读有关 how to live with helm
and ACR
的 Microsoft 教程后,我了解到 az acr helm
命令使用 helm v2,因此已弃用,应使用 OCI
工件。
切换到 OCI 第 1 部分
阅读后我将发布步骤 2. 更改为单行:
helm registry login <acrname>.azurecr.io --username <username> --password <password>
现在在发布步骤 2 中给了我 Login Succeeded
。但是发布步骤 3。失败并显示
Error: failed to download "<acrname>/<reponame>"
.
切换到 OCI 第 2 部分
我认为 helm 任务不兼容或与新方法不兼容,所以我删除了发布步骤 3。并决定在步骤 2 中从命令行进行。所以现在步骤 2 看起来像这样:
helm registry login <acrname>.azurecr.io --username <username> --password <password>
helm upgrade --install --wait -n <namespace> <deploymentName> oci://<acrname>.azurecr.io/<reponame> --version latest --values ./values.yaml
不幸的是,这仍然给我:
Error: failed to download "oci://<acrname>.azurecr.io/<reponame>" at version "latest"
Helm 拉取、导出、升级而不只是升级
接下来的尝试是将 help upgrade
拆分为 helm pull
、helm export
和 helm upgrade
,但
helm pull oci://<acrname>.azurecr.io/<reponame> --version latest
给我:
Error: manifest does not contain minimum number of descriptors (2), descriptors found: 0
将 docker build
和 docker push
任务更改为 v2
我还尝试将构建管道中的 docker 任务更改为 v2。但这根本没有改变任何东西。
您是否尝试过将 Ingress 对象的 apiVersion
更改为 networking.k8s.io/v1beta1
或 networking.k8s.io/v1
? Support for Ingress in the extensions/v1beta1 API version is dropped in k8s 1.22.
我们的 helm chart 中的 ingress.yaml
文件看起来像这样支持多个 k8s 版本。您可以忽略 AWS-specific 注释,因为您使用的是 Azure。我们的图表具有 ingress.enablePathType
的全局值,因为在编写 yaml 文件时,AWS Load Balancer did not support pathType 因此我们将该值设置为 false。
{{- if .Values.global.ingress.enabled -}}
{{- $useV1Ingress := and (.Capabilities.APIVersions.Has "networking.k8s.io/v1/Ingress") .Values.global.ingress.enablePathType -}}
{{- if $useV1Ingress -}}
apiVersion: networking.k8s.io/v1
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
{{- end }}
kind: Ingress
metadata:
name: example-ingress
labels:
{{- include "my-chart.labels" . | nindent 4 }}
annotations:
{{- if .Values.global.ingress.group.enabled }}
alb.ingress.kubernetes.io/group.name: {{ required "ingress.group.name is required when ingress.group.enabled is true" .Values.global.ingress.group.name }}
{{- end }}
{{- with .Values.global.ingress.annotations }}
{{- toYaml . | nindent 4 }}
{{- end }}
# Add these tags to the AWS Application Load Balancer
alb.ingress.kubernetes.io/tags: k8s.namespace/{{ .Release.Namespace }}={{ .Release.Namespace }}
spec:
rules:
- host: {{ include "my-chart.applicationOneServerUrl" . | quote }}
http:
paths:
{{- if $useV1Ingress }}
- path: /
pathType: Prefix
backend:
service:
name: {{ $applicationOneServiceName }}
port:
name: http-grails
{{- else }}
- path: /*
backend:
serviceName: {{ $applicationOneServiceName }}
servicePort: http-grails
{{- end }}
- host: {{ include "my-chart.applicationTwoServerUrl" . | quote }}
http:
paths:
{{- if $useV1Ingress }}
- path: /
pathType: Prefix
backend:
service:
name: {{ .Values.global.applicationTwo.serviceName }}
port:
name: http-grails
{{- else }}
- path: /*
backend:
serviceName: {{ .Values.global.applicationTwo.serviceName }}
servicePort: http-grails
{{- end }}
{{- end }}
只是为了使图片完整 - @wubbalubba 提到图表定义中入口的 YAML 的变化并不是我修复我们的管道必须做的唯一事情:
- 所以首先,很明显,将 ingress 的 YAML 文件中图表定义内的 API 更改为
v1
,并增加图表版本。然后重新打包推送到ACR:
helm package .
helm push .\generated-new-chart.tgz oci://<acrname>.azurecr.io/
- 从 this guide 中学到的下一件事是更新,或者更确切地说,我只是删除了与我的服务相关的所有机密和配置映射:
kubectl delete secret -l owner=helm,status=deployed,name=<release_name> --namespace <release_namespace>
kubectl delete configmap -l owner=helm,status=deployed,name=<release_name> --namespace <release_namespace>
- 最后,删除部署 helm 升级步骤。相反 shell 脚本承担了责任:
helm registry login $(ContainerRegistryUrl) --username $(ContainerRegistryUsername) --password $(ContainerRegistryPassword)
az aks get-credentials --resource-group $(Kubernetes__ResourceGroup) --name $(Kubernetes__Cluster)
helm upgrade --install --wait -n $(NamespaceName) $(ServiceName) oci://$(ContainerRegistryUrl)/services-generic-chart --version 2 -f ./values.yaml
直到那时我才能够成功地重新部署所有内容。