Freigeben über


Tutorial: Verwenden einer Canary-Bereitstellungsstrategie für Kubernetes

Azure DevOps Services | Azure DevOps Server 2022

In dieser schrittweisen Anleitung erfahren Sie, wie Sie die Kubernetes-Manifestaufgabe zusammen mit der canary Strategie verwenden. Bei einer Canary-Bereitstellungsstrategie werden neue Versionen einer Anwendung neben stabilen Produktionsversionen bereitgestellt.

Sie verwenden den zugeordneten Workflow, um den Code bereitzustellen und die Baseline- und Canary-Bereitstellungen zu vergleichen. Basierend auf der Auswertung entscheiden Sie, ob Sie die Canary-Bereitstellung hochstufen oder ablehnen möchten.

In diesem Tutorial werden Docker-Registrierungs- und Azure Resource Manager-Dienstverbindungen zur Herstellung von Verbindungen zu Azure-Ressourcen verwendet. Für einen privaten Azure Kubernetes Service (AKS)-Cluster oder einen Cluster, für den lokale Konten deaktiviert sind, sind Azure Resource Manager-Dienstverbindungen die bessere Möglichkeit, Verbindungen herzustellen.

Voraussetzungen

GitHub-Repositorydateien

Das GitHub-Repository enthält die folgenden Dateien:

Datei Beschreibung
./app/app.py Ein einfacher, Flask-basierter Webserver. Die Datei richtet einen benutzerdefinierten Zähler für die Anzahl der guten und schlechten Antworten ein, basierend auf dem Wert der Variablen success_rate.
./app/Dockerfile Wird bei jeder Änderung von app.py zum Erstellen des Images verwendet. Jede Änderung löst die Buildpipeline aus, um das Image zu erstellen und zur Containerregistrierung zu pushen.
./manifests/deployment.yml Enthält die Spezifikation des sampleapp-Bereitstellungsworkloads, der dem veröffentlichten Image entspricht. Sie verwenden diese Manifestdatei für die stabile Version des Bereitstellungsobjekts und zum Ableiten der Baseline- und Canary-Varianten der Workloads.
./manifests/service.yml Erstellt den sampleapp-Dienst. Dieser Dienst leitet Anforderungen an die Pods weiter, die von den Stable-, Baseline- und Canary-Bereitstellungen gestartet werden.
./misc/fortio.yml Richtet eine Fortio-Bereitstellung ein. Bei dieser Bereitstellung handelt es sich um ein Tool zum Testen der Auslastung, das einen Strom von Anforderungen an den bereitgestellten sampleapp-Dienst sendet. Der Anforderungsstream wird an Pods in den drei Bereitstellungen weitergeleitet: Stable, Baseline und Canary.

Erstellen von Dienstverbindungen

  1. Navigieren Sie im Azure DevOps-Projekt zu Projekteinstellungen>Pipelines>Dienstverbindungen.
  2. Erstellen Sie eine Docker-Registrierungsdienstverbindung namens azure-pipelines-canary-acr, die Ihrer Azure Container Registry-Instanz zugeordnet ist.
  3. Erstellen Sie eine Azure Resource Manager-Dienstverbindung mit der Workload-Identität namens azure-pipelines-canary-k8s für Ihre Ressourcengruppe.

Hinzufügen der Build-Phase

  1. Wechseln Sie im Azure DevOps-Projekt zu Pipelines>Pipeline erstellen oder Neue Pipeline.

  2. Wählen Sie GitHub als Codespeicherort aus. Wählen Sie anschließend Ihr geforktes Repository azure-pipelines-canary-k8s aus.

  3. Wählen Sie auf der Registerkarte Konfigurieren die Option Starterpipeline aus.

  4. Ersetzen Sie auf der Registerkarte Überprüfen den Pipeline-YAML durch den folgenden Code:

    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 repository
      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)
    

    Wenn die von Ihnen erstellte Docker-Registrierungsdienstverbindung einer Containerregistrierung namens example.azurecr.io zugeordnet ist, wird das Image auf example.azurecr.io/azure-pipelines-canary-k8s:$(Build.BuildId) festgelegt.

  5. Wählen Sie Speichern und ausführen aus. Stellen Sie sicher, dass der Auftrag erfolgreich ausgeführt wird.

Bearbeiten der Manifestdatei

Bearbeiten Sie im Repository-Fork manifests/deployment.yml, indem Sie <foobar> durch die URL Ihrer Containerregistrierung ersetzen, z. B. example.azurecr.io/azure-pipelines-canary-k8s.

Einrichten der fortlaufenden Bereitstellung

Jetzt können Sie die kontinuierliche Bereitstellung einrichten, die die Canary-Phase bereitstellen und die Canary-Bereitstellung manuell hochstufen oder ablehnen.

Erstellen einer Umgebung

Sie können die Bereitstellung mit YAML oder klassisch durchführen.

  1. Navigieren Sie im Azure DevOps-Projekt zu Pipelines>Umgebungen. Wählen Sie dann Umgebung erstellen oder Neue Umgebung aus.
  2. Geben Sie im ersten Bildschirm unter Neue Umgebung akscanary in Name ein. Wählen Sie anschließend Kubernetes unter Ressource und dann Weiter aus.
  3. Geben Sie im Bildschirm Kubernetes-Ressource Folgendes ein:
    • Anbieter: Wählen Sie Azure Kubernetes Service aus.
    • Azure-Abonnement: Wählen Sie Ihr Azure-Abonnement aus.
    • Cluster: Wählen Sie Ihren AKS-Cluster aus.
    • Namespace: Wählen Sie Neu aus, und geben Sie canarydemo ein.
  4. Wählen Sie Überprüfen und erstellen aus.

Hinzufügen der Canary-Phase

  1. Navigieren Sie zu Pipelines, und wählen Sie die von Ihnen erstellte Pipeline aus. Wählen Sie anschließend Bearbeiten aus.

  2. Ersetzen Sie den gesamten Pipeline-YAML durch den folgenden Code.

    Dieser Code ändert den Schritt Docker@2, den Sie zuvor zur Verwendung einer Phase ausgeführt haben, und fügt zwei weitere Schritte hinzu, um die Manifeste und die misc-Verzeichnisse als Artefakte für folgende Phasen zu kopieren.

    Der Code verschiebt auch einige Werte zu Variablen, um die Verwendung an späterer Stelle in der Pipeline zu vereinfachen. Ersetzen Sie in der Variablen containerRegistry <example> durch den Namen Ihrer Containerregistrierung.

    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. Fügen Sie am Ende der YAML-Datei eine weitere Phase hinzu, um die Canary-Version bereitzustellen. Ersetzen Sie die Werte my-resource-group und my-aks-cluster mit Ihrer Ressourcengruppe und dem Namen des Azure Kubernetes Service-Clusters.

    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. Wählen Sie Überprüfen und speichern aus, und speichern Sie die Pipeline direkt am Hauptbranch.

Hinzufügen einer manuellen Genehmigung für die Hochstufung oder Ablehnung der Canary-Bereitstellung

Sie können manuell mit YAML oder klassisch eingreifen.

  1. Erstellen Sie eine neue Kubernetes-Umgebung namens akspromote.
  2. Öffnen Sie die neue Umgebung akspromote in der Liste der Umgebungen. Wählen Sie dann Genehmigungen auf der Registerkarte Genehmigungen und Prüfungen aus.
  3. Fügen Sie im Bildschirm Genehmigungen Ihr eigenes Benutzerkonto unter Genehmiger hinzu.
  4. Erweitern Sie Erweitert, und stellen Sie sicher, dass die Option Genehmigern die Genehmigung eigener Ausführungen gestatten ausgewählt ist.
  5. Klicken Sie auf Erstellen.

Hinzufügen von Hochstufungs- und Ablehnungsstufen zur Pipeline

  1. Navigieren Sie zu Pipelines, und wählen Sie die von Ihnen erstellte Pipeline aus. Wählen Sie anschließend Bearbeiten aus.

  2. Fügen Sie die folgende PromoteRejectCanary-Phase am Ende der YAML-Datei hinzu, in der die Änderungen hochgestuft werden.

    - 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. Fügen Sie die folgende RejectCanary-Phase am Ende der Datei hinzu, in der die Änderungen zurückgenommen werden.

    - 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. Wählen Sie Überprüfen und speichern aus, und speichern Sie die Pipeline direkt am Hauptbranch.

Bereitstellen einer stabilen Version

Bei der ersten Ausführung der Pipeline sind die stabile Version der Workloads und ihre Baseline- oder Canary-Versionen nicht im Cluster vorhanden. Sie stellen eine stabile Version des Workloads sampleapp wie folgt bereit.

Sie können eine stabile Version mit YAML oder klassisch bereitstellen.

  1. Ändern Sie success_rate = 50 in app/app.py in success_rate = 100. Diese Änderung löst die Pipeline, das Erstellen und Pushen des Images zur Containerregistrierung sowie die DeployCanary-Phase aus.
  2. Da Sie eine Genehmigung für die Umgebung akspromote konfiguriert haben, wartet die Version, bevor diese Phase ausgeführt wird. Wählen Sie auf der Übersichtsseite für die Buildausführung Überprüfen und dann Genehmigen aus.

Nach der Genehmigung stellt die Pipeline die stabile Version des Workloads sampleapp in manifests/deployment.yml für den Namespace bereit.

Initiieren des Canary-Workflows und Ablehnen der Genehmigung

Die stabile Version des Workloads sampleapp ist jetzt im Cluster vorhanden. Nehmen Sie als Nächstes an der Simulationsanwendung die folgende Änderung vor.

  1. Ändern Sie success_rate = 50 in app/app.py in success_rate = 100. Diese Änderung löst die Pipeline, das Erstellen und Pushen des Images zur Containerregistrierung sowie die DeployCanary-Phase aus.
  2. Da Sie eine Genehmigung für die Umgebung akspromote konfiguriert haben, wartet die Version, bevor diese Phase ausgeführt wird.
  3. Wählen Sie auf der Zusammenfassungsseite „Buildausführung“ die Option Überprüfen und dann Ablehnen im nachfolgenden Dialogfeld aus. Dadurch wird die Bereitstellung abgelehnt.

Nach der Ablehnung verhindert die Pipeline die Codebereitstellung.

Bereinigung

Wenn Sie diese Anwendung nicht weiter verwenden möchten, löschen Sie die Ressourcengruppe im Azure-Portal und das Projekt in Azure DevOps.