教學課程:針對 Kubernetes 使用 Canary 部署策略
Azure DevOps Services |Azure DevOps Server 2022
本逐步指南說明如何搭配canary
策略使用 Kubernetes 指令清單工作。 Canary 部署策略會在穩定且生產版本旁邊部署新版本的應用程式。
您可以使用相關聯的工作流程來部署程式代碼,並比較基準和 Canary 應用程式部署。 根據評估,您決定要升級或拒絕 Canary 部署。
本教學課程使用 Docker Registry 和 Azure Resource Manager 服務連線來連線到 Azure 資源。 針對已停用本機帳戶的 Azure Kubernetes Service (AKS) 私人叢集或叢集, Azure Resource Manager 服務連線 是連線的更好方式。
必要條件
具有至少 用戶 許可權的 Azure DevOps 專案。
Azure 帳戶。 免費建立帳戶。
已部署 Azure Kubernetes Service (AKS) 叢集。 當您部署 AKS 叢集或之後,您可以將 AKS 叢集連結至 Azure Container Registry 叢集。
GitHub 帳戶。 建立免費的 GitHub 帳戶。
GitHub 存放庫的 https://github.com/MicrosoftDocs/azure-pipelines-canary-k8s 分支。
重要
在下列程式中,系統可能會提示您建立 GitHub 服務連線 ,或重新導向至 GitHub 以登入、安裝 Azure Pipelines 或授權 Azure Pipelines。 請遵循畫面上的指示來完成此程式。 如需詳細資訊,請參閱 存取 GitHub 存放庫。
GitHub 存放庫檔案
GitHub 存放庫包含下列檔案:
檔案 | 說明 |
---|---|
./app/app.py | 簡單且以 Flask 為基礎的網頁伺服器 。 檔案會根據變數的值 success_rate ,設定好壞回應數目的自定義計數器。 |
./app/Dockerfile | 用於建置映像,每個變更都會 app.py。 每個變更都會觸發組建管線來建置映像,並將其推送至容器登錄。 |
./manifests/deployment.yml | 包含對應至已發行映像的 sampleapp 部署工作負載規格。 您可以將此指令清單檔用於部署對象的穩定版本,以及衍生工作負載的基準和 Canary 變體。 |
./manifests/service.yml | 建立 sampleapp 服務。 此服務會將要求路由傳送至由穩定、基準和 Canary 部署所啟動的 Pod。 |
./misc/fortio.yml | 設定 fortio 部署。 此部署是負載測試工具,可將要求串流傳送至已 sampleapp 部署的服務。 要求數據流會路由傳送至三個部署下的 Pod:穩定、基準和 Canary。 |
建立服務連線
- 在您的 Azure DevOps 專案中,移至 [項目設定>管線>服務連線]。
- 建立名為 azure-pipelines-canary-acr 的 Docker 登錄服務連線,其與您的 Azure Container Registry 實例相關聯。
- 使用名為 azure-pipelines-canary-k8s 的工作負載身分識別,為您的資源群組建立 Azure Resource Manager 服務連線。
新增建置階段
在您的 Azure DevOps 專案中,移至 [管線建立管線>] 或 [新增管線]。
針對 您的程式代碼位置選取 GitHub ,然後選取分支 的 azure-pipelines-canary-k8s 存放庫。
在 [ 設定] 索引標籤上,選擇 [ 入門管線]。
在 [ 檢閱] 索引標籤上,以下列程式代碼取代管線 YAML。
trigger: - main pool: vmImage: ubuntu-latest variables: imageName: azure-pipelines-canary-k8s # name of ACR image dockerRegistryServiceConnection: azure-pipelines-canary-acr # name of ACR service connection imageRepository: 'azure-pipelines-canary-k8s' # name of image repostory containerRegistry: example.azurecr.io # name of Azure container registry 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)
如果您建立的 Docker 登入服務連線與名為
example.azurecr.io
的容器登錄相關聯,則映像會設定為example.azurecr.io/azure-pipelines-canary-k8s:$(Build.BuildId)
。選取 [ 儲存並執行 ],並確定作業已成功執行。
編輯指令清單檔案
在您的存放庫分支中,編輯 指令清單/deployment.yml ,以取代 <foobar>
為容器登錄的 URL,例如 example.azurecr.io/azure-pipelines-canary-k8s
。
設定持續部署
現在,設定持續部署、部署 Canary 階段,以及透過手動核准來升級或拒絕 Canary。
建立環境
您可以使用 YAML 或傳統部署。
- 在您的 Azure DevOps 專案中,移至 [管線>環境],然後選取 [建立環境] 或 [新增環境]。
- 在第一個 [新增環境] 畫面上,於 [名稱] 底下輸入 akscanary,選取 [資源] 下的 [Kubernetes],然後選取 [下一步]。
- 填寫 Kubernetes 資源畫面,如下所示:
- 提供者:選取 [Azure Kubernetes Service]。
- Azure 訂用帳戶:選取您的 Azure 訂用帳戶。
- 叢集:選取您的 AKS 叢集。
- Namespace:選取 [ 新增 ],然後輸入 canarydemo。
- 選取 [驗證並建立]。
新增 Canary 階段
移至 [管線],選取您建立的管線,然後選取 [ 編輯]。
以下列程式代碼取代整個管線 YAML。
此程式代碼會
Docker@2
變更您先前執行的步驟以使用階段,並新增兩個步驟,將指令清單和 misc 目錄複製為成品,以供連續階段使用。程序代碼也會將某些值移至變數,以便稍後在管線中使用。 在變數中
containerRegistry
,將 取代<example>
為容器登錄的名稱。trigger: - main pool: vmImage: ubuntu-latest variables: imageName: azure-pipelines-canary-k8s dockerRegistryServiceConnection: azure-pipelines-canary-acr imageRepository: 'azure-pipelines-canary-k8s' containerRegistry: <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 版本。 將 值
my-resource-group
my-aks-cluster
取代為您的資源群組和 Azure Kubernetes Service 叢集名稱。trigger: - main pool: vmImage: ubuntu-latest variables: imageName: azure-pipelines-canary-k8s dockerRegistryServiceConnection: azure-pipelines-canary-acr imageRepository: 'azure-pipelines-canary-k8s' containerRegistry: yourcontainerregistry.azurecr.io #update with container registry 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 - stage: DeployCanary displayName: Deploy canary dependsOn: Build condition: succeeded() jobs: - deployment: Deploycanary displayName: Deploy canary pool: vmImage: ubuntu-latest environment: 'akscanary' strategy: runOnce: deploy: steps: - task: KubernetesManifest@1 displayName: Create Docker Registry Secret inputs: action: 'createSecret' connectionType: 'azureResourceManager' azureSubscriptionConnection: 'azure-pipelines-canary-sc' azureResourceGroup: 'my-resource-group' kubernetesCluster: 'my-aks-cluster' secretType: 'dockerRegistry' secretName: 'my-acr-secret' dockerRegistryEndpoint: 'azure-pipelines-canary-acr' - task: KubernetesManifest@1 displayName: Deploy to Kubernetes cluster inputs: action: 'deploy' connectionType: 'azureResourceManager' azureSubscriptionConnection: 'azure-pipelines-canary-sc' azureResourceGroup: 'my-resource-group' kubernetesCluster: 'my-aks-cluster' strategy: 'canary' percentage: '25' manifests: | $(Pipeline.Workspace)/manifests/deployment.yml $(Pipeline.Workspace)/manifests/service.yml containers: '$(containerRegistry)/$(imageRepository):$(tag)' imagePullSecrets: 'my-acr-secret' - task: KubernetesManifest@1 displayName: Deploy Forbio to Kubernetes cluster inputs: action: 'deploy' connectionType: 'azureResourceManager' azureSubscriptionConnection: 'azure-pipelines-canary-sc' azureResourceGroup: 'my-resource-group' kubernetesCluster: 'my-aks-cluster' manifests: '$(Pipeline.Workspace)/misc/*'
選取 [ 驗證並儲存],然後將管線直接儲存至主要分支。
新增手動核准以升級或拒絕 Canary 部署
您可以使用 YAML 或傳統手動介入。
- 建立名為 akspromote 的新 Kubernetes 環境。
- 從環境清單中開啟新的 akspromote 環境,然後選取 [核准和檢查] 索引卷標上的 [核准]。
- 在 [核准] 畫面上,在 [核准者] 底下新增您自己的用戶帳戶。
- 展開 [ 進階],並確定 已選取 [允許核准者核准自己的執行 ]。
- 選取 建立。
將升階和拒絕階段新增至管線
移至 [管線],選取您建立的管線,然後選取 [ 編輯]。
在 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' strategy: runOnce: deploy: steps: - task: KubernetesManifest@1 displayName: Create Docker Registry Secret for akspromote inputs: action: 'createSecret' connectionType: 'azureResourceManager' azureSubscriptionConnection: 'azure-pipelines-canary-sc' azureResourceGroup: 'my-resource-group' kubernetesCluster: 'my-aks-cluster' secretType: 'dockerRegistry' secretName: 'my-acr-secret' dockerRegistryEndpoint: 'azure-pipelines-canary-acr' - task: KubernetesManifest@1 displayName: promote canary inputs: action: 'promote' connectionType: 'azureResourceManager' azureSubscriptionConnection: 'azure-pipelines-canary-sc' azureResourceGroup: 'my-resource-group' kubernetesCluster: 'my-aks-cluster' strategy: 'canary' manifests: '$(Pipeline.Workspace)/manifests/*' containers: '$(containerRegistry)/$(imageRepository):$(tag)' imagePullSecrets: 'my-acr-secret' ```
在復原變更的檔案結尾新增下列
RejectCanary
階段。- stage: RejectCanary displayName: Reject canary dependsOn: PromoteRejectCanary condition: failed() jobs: - deployment: RejectCanary displayName: Reject Canary pool: vmImage: ubuntu-latest environment: 'akscanary' strategy: runOnce: deploy: steps: - task: KubernetesManifest@1 displayName: Create Docker Registry Secret for reject canary inputs: action: 'createSecret' connectionType: 'azureResourceManager' azureSubscriptionConnection: 'azure-pipelines-canary-sc' azureResourceGroup: 'kubernetes-testing' kubernetesCluster: 'my-aks-cluster' secretType: 'dockerRegistry' secretName: 'my-acr-secret' dockerRegistryEndpoint: 'azure-pipelines-canary-acr' - task: KubernetesManifest@1 displayName: Reject canary deployment inputs: action: 'reject' connectionType: 'azureResourceManager' azureSubscriptionConnection: 'azure-pipelines-canary-sc' azureResourceGroup: 'my-resource-group' kubernetesCluster: 'my-aks-cluster' namespace: 'default' strategy: 'canary' manifests: '$(Pipeline.Workspace)/manifests/*' ```
選取 [ 驗證並儲存],然後將管線直接儲存至主要分支。
部署穩定版本
針對管線的第一次執行,工作負載的穩定版本及其基準或 Canary 版本不存在於叢集中。 部署穩定版本的工作負載, sampleapp
如下所示。
您可以使用 YAML 或傳統部署穩定版本。
- 在 app/app.py 中,將 變更
success_rate = 50
為success_rate = 100
。 這項變更會觸發管線、建置映射並將映像推送至容器登錄,也會觸發DeployCanary
階段。 - 因為您已在環境上
akspromote
設定核准,發行會在執行該階段之前等候。 在 [組建執行摘要] 頁面上,選取 [ 檢閱 ],然後選取 [ 核准]。
核准之後,管線會將指令清單/deployment.yml中工作負載的sampleapp
穩定版本部署到命名空間。
起始 Canary 工作流程並拒絕核准
工作負載的 sampleapp
穩定版本現在存在於叢集中。 接下來,對模擬應用程式進行下列變更。
- 在 app/app.py 中,將 變更
success_rate = 50
為success_rate = 100
。 這項變更會觸發管線、建置映射並將映像推送至容器登錄,也會觸發DeployCanary
階段。 - 因為您已在環境上
akspromote
設定核准,發行會在執行該階段之前等候。 - 在 [組建執行摘要] 頁面上,選取 [檢閱 ],然後在後續對話框中選取 [ 拒絕 ]。 這會拒絕部署。
拒絕之後,管線會防止程序代碼部署。
清理
如果您不打算繼續使用此應用程式,請刪除 Azure 入口網站 中的資源群組和 Azure DevOps 中的專案。