Kubernetes 部署的 Canary 部署策略
Azure DevOps Services
Canary 部署策略意味着在稳定的生产版本旁边部署应用程序的新版本。 然后,可以查看 Canary 版本与基线的比较方式,然后再升级或拒绝部署。
本分步指南介绍如何使用 Kubernetes 清单任务的 Canary 策略。 具体来说,你将了解如何为 Kubernetes 设置 Canary 部署以及用于评估代码的关联工作流。 然后,使用该代码比较基线和 Canary 应用部署,以便你可以决定是推广还是拒绝 Canary 部署。
先决条件
- 具有活动订阅的 Azure 帐户。 免费创建帐户。
- 一个 GitHub 帐户。 创建一个免费的 GitHub 帐户(如果没有)。
- 具有推送权限的Azure 容器注册表、Google 容器注册表或Docker Hub注册表。 如果还没有Azure 容器注册表,请创建一个。
- Kubernetes 群集 (,例如Azure Kubernetes 服务、Google Kubernetes 引擎或 Amazon Elastic Kubernetes 服务) 。 部署 Azure Kubernetes 服务 (AKS) 群集。
代码示例
在GitHub上分叉以下存储库。
https://github.com/MicrosoftDocs/azure-pipelines-canary-k8s
下面简要概述了本指南中使用的存储库中的文件:
- ./app:
- app.py - 一个简单的基于 Flask 的 Web 服务器,它通过使用 适用于 Python 应用程序的 Prometheus 检测库进行检测。 根据变量的值
success_rate,为给定的好响应和坏响应数设置自定义计数器。 - Dockerfile - 用于生成映像,每次对 app.py 进行更改。 每次更改时,都会触发生成管道,并生成映像并将其推送到容器注册表。
- app.py - 一个简单的基于 Flask 的 Web 服务器,它通过使用 适用于 Python 应用程序的 Prometheus 检测库进行检测。 根据变量的值
- ./manifests:
- deployment.yml - 包含与之前发布的映像相对应的部署工作负荷的
sampleapp规范。 你不仅将此清单文件用于稳定版本的部署对象,还用于派生工作负荷的基线和 Canary 变体。 - service.yml - 创建
sampleapp服务。 此服务会将请求路由到前面提到的部署 (稳定、基线和 canary) 启动的 Pod。
- deployment.yml - 包含与之前发布的映像相对应的部署工作负荷的
- ./misc
- service-monitor.yml - 用于设置 ServiceMonitor 对象。 此对象设置 Prometheus 指标擦除。
- fortio-deploy.yml - 用于设置 fortio 部署。 此部署稍后用作负载测试工具,用于将请求流发送到
sampleapp之前部署的服务。 所有三个部署下发送到sampleappPod 的请求流 (稳定、基线和 canary) 。
备注
本指南使用 Prometheus 进行代码检测和监视。 任何等效的解决方案(如Azure 应用程序 Insights)都可以用作替代方法。
安装 prometheus-operator
若要在群集上安装 Prometheus,请使用开发计算机上的以下命令。 必须安装 kubectl 和 Helm,并且必须将上下文设置为要对其部署的群集。 Grafana 稍后用于可视化仪表板上的基线和金丝雀指标,作为此 Helm 图表的一部分安装。
helm install --name sampleapp stable/prometheus-operator
创建服务连接
- 转到Project设置>Pipelines>服务连接。
- 创建与容器注册表关联的 Docker 注册表服务连接 。 将其命名 为 azure-pipelines-canary-k8s。
- 为要部署到的 Kubernetes 群集和命名空间创建 Kubernetes 服务连接 。 将其命名 为 azure-pipelines-canary-k8s。
设置持续集成
转到 Pipelines>Create Pipeline,然后选择存储库。
在“ 配置 ”选项卡上,选择 “启动器管道”。
在“ 审阅 ”选项卡上,将管道 YAML 替换为此代码。
trigger: - main pool: vmImage: ubuntu-latest variables: imageName: azure-pipelines-canary-k8s steps: - task: Docker@2 displayName: Build and push image inputs: containerRegistry: azure-pipelines-canary-k8s #replace with name of your Docker registry service connection repository: $(imageName) command: buildAndPush Dockerfile: app/Dockerfile tags: | $(Build.BuildId)如果创建的 Docker 注册表服务连接与
example.azurecr.io该连接相关联,则映像example.azurecr.io/azure-pipelines-canary-k8s:$(Build.BuildId)将基于前面的配置。
编辑清单文件
在 manifests/deployment.yml 中,替换为 <example> 容器注册表的 URL。 例如,替换后,图像字段应如下所示 contosodemo.azurecr.io/azure-pipelines-canary-k8s。
设置连续部署
以下部分提供了设置持续部署的步骤,包括如何部署 Canary 阶段,以及如何通过手动干预促进或拒绝 Canary。
部署 Canary 阶段
可以使用 YAML 或经典部署模型进行部署。
转到 Pipelines>EnvironmentsCreate>环境。
创建新环境。
- 名称: akscanary
- 资源:选择 Kubernetes。
选择 “下一步”,并按如下所示配置 Kubernetes 资源:
- 提供程序:Azure Kubernetes 服务
- Azure 订阅:选择保存 Kubernetes 群集的订阅。
- 群集:选择群集。
- 命名空间:使用名称 canarydemo 创建新命名空间。
选择 “验证”和“创建”。
转到“管道”。 选择创建的管道,然后选择“ 编辑”。
将之前创建的步骤更改为现在使用阶段。 再添加两个步骤,将清单和 杂项 目录复制为项目,供连续阶段使用。 你可能还希望将几个值移动到变量,以便稍后在管道中更轻松地使用。 现在,完整的 YAML 应如下所示:
trigger: - main pool: vmImage: ubuntu-latest variables: imageName: azure-pipelines-canary-k8s dockerRegistryServiceConnection: dockerRegistryServiceConnectionName #replace with name of your Docker registry service connection imageRepository: 'azure-pipelines-canary-k8s' containerRegistry: example.azurecr.io #replace with the name of your container registry, Should be in the format example.azurecr.io tag: '$(Build.BuildId)' stages: - stage: Build displayName: Build stage jobs: - job: Build displayName: Build pool: vmImage: ubuntu-latest steps: - task: Docker@2 displayName: Build and push image inputs: containerRegistry: $(dockerRegistryServiceConnection) repository: $(imageName) command: buildAndPush Dockerfile: app/Dockerfile tags: | $(tag) - publish: manifests artifact: manifests - publish: misc artifact: misc在 YAML 文件末尾添加阶段以部署 Canary 版本。
- stage: DeployCanary displayName: Deploy canary dependsOn: Build condition: succeeded() jobs: - deployment: Deploycanary displayName: Deploy canary pool: vmImage: ubuntu-latest environment: 'akscanary.canarydemo' strategy: runOnce: deploy: steps: - task: KubernetesManifest@0 displayName: Create imagePullSecret inputs: action: createSecret secretName: azure-pipelines-canary-k8s dockerRegistryEndpoint: azure-pipelines-canary-k8s - task: KubernetesManifest@0 displayName: Deploy to Kubernetes cluster inputs: action: 'deploy' strategy: 'canary' percentage: '25' manifests: | $(Pipeline.Workspace)/manifests/deployment.yml $(Pipeline.Workspace)/manifests/service.yml containers: '$(containerRegistry)/$(imageRepository):$(tag)' imagePullSecrets: azure-pipelines-canary-k8s - task: KubernetesManifest@0 displayName: Deploy Forbio and ServiceMonitor inputs: action: 'deploy' manifests: | $(Pipeline.Workspace)/misc/*通过直接提交到主分支来保存管道。 此提交应已成功运行管道。
手动干预来推广或拒绝 Canary
可以使用 YAML 或使用经典部署模型手动干预。
转到 Pipelines>EnvironmentsNew>环境。
配置新环境。
- 名称: akspromote
- 资源:选择 Kubernetes。
选择 “下一步”,并按如下所示配置 Kubernetes 资源:
- 提供程序:Azure Kubernetes 服务
- Azure 订阅:选择保存 Kubernetes 群集的订阅。
- 群集:选择群集。
- 命名空间:选择前面创建的命名空间 canarydemo。
选择 “验证”和“创建”。
从环境列表中选择新
akspromote环境。选择审批并检查>审批。 然后选择省略号图标 (三个点) 。
按如下所示配置审批:
- 审批者:添加自己的用户帐户。
- 高级:确保已选择 “允许审批者批准自己的运行 ”框。
选择“创建”。
转到Pipelines,然后选择刚刚创建的管道。 然后选择“编辑”。
在 YAML 文件的末尾添加另一个阶段
PromoteRejectCanary,以提升更改。- stage: PromoteRejectCanary displayName: Promote or Reject canary dependsOn: DeployCanary condition: succeeded() jobs: - deployment: PromoteCanary displayName: Promote Canary pool: vmImage: ubuntu-latest environment: 'akspromote.canarydemo' strategy: runOnce: deploy: steps: - task: KubernetesManifest@0 displayName: promote canary inputs: action: 'promote' strategy: 'canary' manifests: '$(Pipeline.Workspace)/manifests/*' containers: '$(containerRegistry)/$(imageRepository):$(tag)' imagePullSecrets: '$(imagePullSecret)'在 YAML 文件末尾添加另一个阶段
RejectCanary以回滚更改。- stage: RejectCanary displayName: Reject canary dependsOn: PromoteRejectCanary condition: failed() jobs: - deployment: RejectCanary displayName: Reject Canary pool: vmImage: ubuntu-latest environment: 'akscanary.canarydemo' strategy: runOnce: deploy: steps: - task: KubernetesManifest@0 displayName: reject canary inputs: action: 'reject' strategy: 'canary' manifests: '$(Pipeline.Workspace)/manifests/*'通过选择 “保存”保存 YAML 管道,然后将其直接提交到主分支。
部署稳定版本
可以使用 YAML 或使用经典部署模型来部署稳定版本。
目前,对于管道的第一次运行,群集中既不存在工作负荷的稳定版本,也不存在其基线版本或 Canary 版本。 若要部署稳定版本,请执行以下部署:
- 在 app/app.py 中,更改为
success_rate = 5success_rate = 10. 此更改触发管道,导致映像生成并将映像推送到容器注册表。 它还将触发阶段DeployCanary。 - 由于你在环境中配置了审批
akspromote,因此发布将在运行该阶段之前等待。 - 在运行摘要中,选择 ReviewApprove>。 这样会将 (清单/deployment.yml) 中的部署的工作负荷稳定版本
sampleapp部署到命名空间。
启动 canary 工作流
工作负荷 sampleapp 的稳定版本现在存在于群集中。 接下来,对模拟应用程序进行以下更改:
在 app/app.py 中,更改为 success_rate = 10success_rate = 20.
此更改会触发生成管道,从而生成映像并将其推送到容器注册表。 此过程反过来会触发发布管道,并开始 部署 Canary 阶段。
模拟请求
在开发计算机上运行以下命令,并使其保持运行状态,以在服务中 sampleapp 发送持续的请求流。 sampleapp通过稳定sampleapp部署将请求路由到 Pod,并将请求路由到由部署sampleapp-canary启动的 sampleapp-baseline Pod。 指定的 sampleapp 选择器适用于所有这些 Pod。
FORTIO_POD=$(kubectl get pod | grep fortio | awk '{ print $1 }')
kubectl exec -it $FORTIO_POD -c fortio /usr/bin/fortio -- load -allow-initial-errors -t 0 http://sampleapp:8080/
设置 Grafana 仪表板
在本地开发计算机上运行以下端口转发命令,以便能够访问 Grafana。
kubectl port-forward svc/sampleapp-grafana 3000:80在浏览器中,打开以下 URL。
http://localhost:3000/login当系统提示输入凭据时,除非
adminPassword在 Helm 图表安装期间prometheus-operator重写了该值,否则可以使用以下值:- 用户名:管理员
- password:prom-operator
从左侧菜单中,选择“+>仪表板>Graph。
选择新添加的面板上的任意位置,然后键入
e以编辑面板。在“ 指标 ”选项卡上,输入以下查询:
rate(requests_total{pod=~"sampleapp-.*", custom_status="good"}[1m])在“ 常规 ”选项卡上,将此面板的名称更改为 “所有示例应用”Pod。
在页面顶部的概述栏中,将持续时间范围更改为 “过去 5 分钟 ”或 “过去 15 分钟”。
若要保存此面板,请选择概述栏中的“保存”图标。
前面的面板可视化来自所有变体的成功率指标。 其中包括部署) 中的
sampleapp稳定 (、部署) 的sampleapp-baseline基线 (,以及部署) 中的sampleapp-canarycanary (。 请注意,可以通过添加另一个面板来仅可视化基线指标和 Canary 指标,并使用以下配置:- 在“ 常规 ”选项卡上,对于 “标题”,选择 sampleapp 基线和 canary。
- 在“ 指标 ”选项卡上,使用以下查询:
rate(requests_total{pod=~"sampleapp-baseline-.*|sampleapp-canary-.*", custom_status="good"}[1m])注意
基线指标和金丝雀指标面板仅在某些条件下具有可用于比较的指标。 这些条件是在 部署 canary 阶段成功完成时, 升级/拒绝 Canary 阶段正在等待手动干预。
提示
为 Grafana 仪表板设置批注,以直观地描绘部署 Canary 和 Promote/reject canary 的阶段完成事件。 这有助于你了解何时开始将基线与 Canary 进行比较,以及何时分别完成了 Canary 的促销或拒绝。
比较基线和金丝雀
此时,部署 canary 阶段已根据从)
1020更改为success_rate(成功完成 (。 升级/拒绝 Canary 阶段正在等待手动干预。 现在可以比较由 Grafana 仪表板中基线和金丝雀变体) 确定custom_status=good的成功率 (。 它应类似于以下内容:
根据对金丝雀的成功率较高的观察,促进金丝雀。 在手动干预任务中选择 “恢复 ”。