分享方式:


教學課程:針對 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 服務連線 是連線的更好方式。

必要條件

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。

建立服務連線

  1. 在您的 Azure DevOps 專案中,移至 [項目設定>管線>服務連線]。
  2. 建立名為 azure-pipelines-canary-acr 的 Docker 登錄服務連線,其與您的 Azure Container Registry 實例相關聯。
  3. 使用名為 azure-pipelines-canary-k8s 的工作負載身分識別,為您的資源群組建立 Azure Resource Manager 服務連線。

新增建置階段

  1. 在您的 Azure DevOps 專案中,移至 [管線建立管線>] 或 [新增管線]。

  2. 針對 您的程式代碼位置選取 GitHub ,然後選取分支 的 azure-pipelines-canary-k8s 存放庫。

  3. 在 [ 設定] 索引標籤上,選擇 [ 入門管線]。

  4. 在 [ 檢閱] 索引標籤上,以下列程式代碼取代管線 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)

  5. 選取 [ 儲存並執行 ],並確定作業已成功執行。

編輯指令清單檔案

在您的存放庫分支中,編輯 指令清單/deployment.yml ,以取代 <foobar> 為容器登錄的 URL,例如 example.azurecr.io/azure-pipelines-canary-k8s

設定持續部署

現在,設定持續部署、部署 Canary 階段,以及透過手動核准來升級或拒絕 Canary。

建立環境

您可以使用 YAML 或傳統部署。

  1. 在您的 Azure DevOps 專案中,移至 [管線>環境],然後選取 [建立環境] 或 [新增環境]。
  2. 在第一個 [新增環境] 畫面上,於 [名稱] 底下輸入 akscanary,選取 [資源] 下的 [Kubernetes],然後選取 [下一步]。
  3. 填寫 Kubernetes 資源畫面,如下所示:
    • 提供者:選取 [Azure Kubernetes Service]。
    • Azure 訂用帳戶:選取您的 Azure 訂用帳戶。
    • 叢集:選取您的 AKS 叢集。
    • Namespace:選取 [ 新增 ],然後輸入 canarydemo
  4. 選取 [驗證並建立]

新增 Canary 階段

  1. 移至 [管線],選取您建立的管線,然後選取 [ 編輯]。

  2. 以下列程式代碼取代整個管線 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
    
  3. 在 YAML 檔案結尾新增另一個階段,以部署 Canary 版本。 將 值my-resource-groupmy-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/*'
    
  4. 選取 [ 驗證並儲存],然後將管線直接儲存至主要分支。

新增手動核准以升級或拒絕 Canary 部署

您可以使用 YAML 或傳統手動介入。

  1. 建立名為 akspromote 的新 Kubernetes 環境。
  2. 從環境清單中開啟新的 akspromote 環境,然後選取 [核准和檢查] 索引卷標上的 [核准]。
  3. 在 [核准] 畫面上,在 [核准者] 底下新增您自己的用戶帳戶。
  4. 展開 [ 進階],並確定 已選取 [允許核准者核准自己的執行 ]。
  5. 選取 建立

將升階和拒絕階段新增至管線

  1. 移至 [管線],選取您建立的管線,然後選取 [ 編輯]。

  2. 在 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'
        ```
    
    
  3. 在復原變更的檔案結尾新增下列 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/*'
        ```
    
  4. 選取 [ 驗證並儲存],然後將管線直接儲存至主要分支。

部署穩定版本

針對管線的第一次執行,工作負載的穩定版本及其基準或 Canary 版本不存在於叢集中。 部署穩定版本的工作負載, sampleapp 如下所示。

您可以使用 YAML 或傳統部署穩定版本。

  1. app/app.py 中,將 變更 success_rate = 50success_rate = 100。 這項變更會觸發管線、建置映射並將映像推送至容器登錄,也會觸發 DeployCanary 階段。
  2. 因為您已在環境上 akspromote 設定核准,發行會在執行該階段之前等候。 在 [組建執行摘要] 頁面上,選取 [ 檢閱 ],然後選取 [ 核准]。

核准之後,管線會將指令清單/deployment.yml工作負載的sampleapp穩定版本部署到命名空間。

起始 Canary 工作流程並拒絕核准

工作負載的 sampleapp 穩定版本現在存在於叢集中。 接下來,對模擬應用程式進行下列變更。

  1. app/app.py 中,將 變更 success_rate = 50success_rate = 100。 這項變更會觸發管線、建置映射並將映像推送至容器登錄,也會觸發 DeployCanary 階段。
  2. 因為您已在環境上 akspromote 設定核准,發行會在執行該階段之前等候。
  3. 在 [組建執行摘要] 頁面上,選取 [檢閱 ],然後在後續對話框中選取 [ 拒絕 ]。 這會拒絕部署。

拒絕之後,管線會防止程序代碼部署。

清理

如果您不打算繼續使用此應用程式,請刪除 Azure 入口網站 中的資源群組和 Azure DevOps 中的專案。