Tutorial: Verwenden einer Canary-Bereitstellungsstrategie für Kubernetes-Bereitstellungen

Azure DevOps Services | Azure DevOps Server 2022

Eine Canary-Bereitstellungsstrategie sieht die Bereitstellung neuer Versionen einer Anwendung neben stabilen Produktionsversionen vor. Sie können dann erkennen, wie die Canary-Version im Vergleich zur Baseline abschneidet, ehe Sie die Bereitstellung höherstufen oder ablehnen.

In dieser Schritt-für-Schritt-Anleitung wird erläutert, wie Sie die Canary-Strategie für die Kubernetes-Manifestaufgabe umsetzen. Insbesondere erfahren Sie, wie Sie Canary-Bereitstellungen für Kubernetes und den zugehörigen Workflow zum Bewerten von Code einrichten. Anschließend vergleichen Sie anhand dieses Codes Baseline- und Canary-App-Bereitstellungen, sodass Sie entscheiden können, ob sie die Canary-Bereitstellung höherstufen oder ablehnen.

Wenn Sie Azure Kubernetes Service verwenden, ist der Azure Resource Manager-Dienstverbindungstyp die beste Möglichkeit, eine Verbindung mit einem privaten Cluster oder einem Cluster mit deaktivierten lokalen Konten herzustellen.

Voraussetzungen

Beispielcode

Forken Sie das folgende Repository auf GitHub.

https://github.com/MicrosoftDocs/azure-pipelines-canary-k8s

Hier finden Sie eine Kurzübersicht über die Dateien im Repository, die in dieser Anleitung verwendet werden:

  • ./app:
    • app.py: ein einfacher, auf Flask basierender Webserver, der mithilfe der Prometheus-Instrumentierungsbibliothek für Python-Anwendungen instrumentiert ist. Ein benutzerdefinierter Zähler wird für die Anzahl von guten und schlechten Antworten eingerichtet, die basierend auf dem Wert der Variablen success_rate ausgegeben werden.
    • Dockerfile: dient zum Erstellen des Images mit jeder an app.py erfolgten Änderung. Bei jeder Änderung wird die Buildpipeline ausgelöst, das Image erstellt und in die Containerregistrierung gepusht.
  • ./manifests:
    • deployment.yml: enthält die Spezifikation der Bereitstellungsworkload von sampleapp, die dem zuvor veröffentlichten Image entspricht. Sie verwenden diese Manifestdatei nicht nur für die stabile Version des Bereitstellungsobjekts, sondern auch für die Ableitung der Baseline- und Canary-Varianten der Workloads.
    • service.yml: dient zum Erstellen des sampleapp-Diensts. Dieser Dienst leitet Anforderungen an die Pods weiter, die von den zuvor erwähnten Bereitstellungen (Stabil, Baseline und Canary) bereitgestellt werden.
  • ./misc
    • service-monitor.yml: dient zum Einrichten eines ServiceMonitor-Objekts. Dieses Objekt richtet das Scraping von Prometheus-Metriken ein.
    • fortio-deploy.yml: dient zum Einrichten einer fortio-Bereitstellung. Diese Bereitstellung wird später als Tool für Auslastungstests verwendet, um einen Datenstrom von Anforderungen an den zuvor bereitgestellten sampleapp-Dienst zu senden. Der Datenstrom der an sampleapp gesendeten Anforderungen wird unter allen drei Bereitstellungen (Stabil, Baseline und Canary) an Pods weitergeleitet.

Hinweis

In diesem Leitfaden verwenden Sie für Codeinstrumentierung und Überwachung Prometheus. Alternativ kann eine gleichwertige Lösung, wie z. B. Azure Application Insights, zum Einsatz kommen.

Installieren von prometheus-operator

Zum Installieren von Prometheus in Ihrem Cluster führen Sie auf Ihrem Entwicklungscomputer den folgenden Befehl aus. kubectl und Helm müssen installiert sein, und Sie müssen den Kontext auf den Cluster festlegen, für den Sie die Bereitstellung vornehmen möchten. Grafana, das Sie später zum Visualisieren der Baseline- und Canary-Metriken in Dashboards nutzen, wird als Teil dieses Helm-Diagramms installiert.

Sie fügen zuerst das Prometheus Community Kubernetes Helm Charts Repository zu Ihrer Helm-Installation hinzu. Anschließend installieren Sie den kube-prometheus-Stapel, eine Sammlung von Kubernetes-Manifesten, Grafana-Dashboards und Prometheus-Regeln.

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update # update local cache
helm install --name sampleapp  prometheus-community/kube-prometheus-stack

Erstellen von Dienstverbindungen

  1. Navigieren Sie im Azure DevOps-Menü zu Projekteinstellungen>Pipelines>Dienstverbindungen.
  2. Erstellen Sie eine Docker-Registrierungsdienstverbindung, die Ihrer Containerregistrierung zugeordnet ist. Nennen Sie sie azure-pipelines-canary-k8s.
  3. Erstellen Sie eine Kubernetes-Dienstverbindung für den Kubernetes-Cluster und -Namespace, in dem die Bereitstellung erfolgen soll. Nennen Sie sie azure-pipelines-canary-k8s.

Hinweis

Wenn Sie Azure Kubernetes Service verwenden, ist der Azure Resource Manager-Dienstverbindungstyp die beste Möglichkeit, eine Verbindung mit einem privaten Cluster oder einem Cluster mit deaktivierten lokalen Konten herzustellen.

Einrichten von Continuous Integration

  1. Wechseln Sie zu Pipelines>Pipeline erstellen, und wählen Sie Ihr Repository aus.

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

  3. Ersetzen Sie auf der Registerkarte Überprüfen den YAML-Code der Pipeline durch diesen Code.

    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)
    

    Wenn die von Ihnen erstellte Docker-Registrierungsdienstverbindung example.azurecr.io zugeordnet ist, wird das Image auf Grundlage der vorherigen Konfiguration mit example.azurecr.io/azure-pipelines-canary-k8s:$(Build.BuildId) verbunden.

Bearbeiten der Manifestdatei

Ersetzen Sie <example> in manifests/deployment.yml durch die URL Ihrer Containerregistrierung. Nach Ersetzen sollte das Feld „Image“ beispielsweise etwa so contosodemo.azurecr.io/azure-pipelines-canary-k8s aussehen.

Einrichten der fortlaufenden Bereitstellung

In den folgenden Abschnitten erfahren Sie, wie Sie Continuous Deployment einrichten, die Canary-Phase bereitstellen und das Canary-Projekt durch manuelle Eingriffe höherstufen oder ablehnen können.

Bereitstellen der Canary-Phase

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

  1. Wechseln Sie zu Pipelines>Umgebungen>Umgebung erstellen.

  2. Erstellen Sie eine neue Umgebung.

    • Name: akscanary
    • Ressource: Wählen Sie Kubernetes.
  3. Wählen Sie Weiter aus, und konfigurieren Sie Ihre Kubernetes-Ressource wie folgt:

    • Anbieter: Azure Kubernetes Service
    • Azure-Abonnement: Wählen Sie das Abonnement mit Ihrem Kubernetes-Cluster.
    • Cluster-: Wählen Sie Ihren Cluster aus.
    • Namespace: Erstellen Sie einen neuen Namespace mit dem Namen canarydemo.
  4. Wählen Sie Überprüfen und erstellen aus.

  5. Navigieren Sie zu Pipelines. Wählen Sie die Pipeline aus, die Sie erstellt haben, und dann Bearbeiten aus.

  6. Ändern Sie den zuvor erstellten Schritt so, dass nun eine Phase verwendet wird. Fügen Sie zwei weitere Schritte hinzu, um die Manifeste und misc-Verzeichnisse als Artefakte zur Verwendung durch aufeinander folgende Phasen zu kopieren. Möglicherweise möchten Sie auch ein paar Werte in Variablen verlagern, um sie später in Ihrer Pipeline leichter verwenden zu können. Ihr vollständiger YAML-Code sollte nun wie folgt aussehen.

    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
    
  7. Fügen Sie am Ende Ihrer YAML-Datei eine Phase hinzu, um die Canary-Version bereitzustellen.

    - 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/*
    
  8. Speichern Sie Ihre Pipeline durch einen direkten Commit im Mainbranch. Durch diesen Commit sollte Ihre Pipeline bereits erfolgreich ausgeführt werden.

Manuelles Eingreifen zum Höherstufen oder Ablehnen des Canarys

Sie können manuell mit YAML oder klassisch eingreifen.

  1. Wechseln Sie zu Pipelines>Umgebungen>Neue Umgebung.

  2. Konfigurieren Sie die neue Umgebung.

    • Name: akspromote
    • Ressource: Wählen Sie Kubernetes.
  3. Wählen Sie Weiter aus, und konfigurieren Sie Ihre Kubernetes-Ressource wie folgt:

    • Anbieter: Azure Kubernetes Service
    • Azure-Abonnement: Wählen Sie das Abonnement mit Ihrem Kubernetes-Cluster.
    • Cluster: Wählen Sie Ihren Cluster.
    • Namespace: Wählen Sie den zuvor erstellten Namespace canarydemo.
  4. Wählen Sie Überprüfen und erstellen aus.

  5. Wählen Sie in der Liste der Umgebungen Ihre neue akspromote-Umgebung aus.

  6. Wählen Sie Genehmigungen und Überprüfungen>Genehmigungen aus. Wählen Sie dann das Auslassungssymbol (die drei Punkte) aus.

  7. Konfigurieren Sie Ihre Genehmigung wie folgt:

    • Genehmigende Personen: Fügen Sie Ihr eigenes Benutzerkonto hinzu.
    • Erweitert: Stellen Sie sicher, dass das Kontrollkästchen Genehmigern erlauben, ihre eigenen Ausführungen zu genehmigen aktiviert ist.
  8. Klicken Sie auf Erstellen.

  9. Wechseln Sie zu Pipelines, und wählen Sie die Pipeline aus, die Sie erstellt haben. Klicken Sie dann auf Bearbeiten.

  10. Fügen Sie eine weitere Phase, PromoteRejectCanary, am Ende Ihrer YAML-Datei hinzu, um die Änderungen höherzustufen.

    - 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)'
    
  11. Fügen Sie eine weitere Phase, RejectCanary, am Ende Ihrer YAML-Datei hinzu, um für die Änderungen ein Rollback auszuführen.

    - 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/*'
    
  12. Speichern Sie Ihre YAML-Pipeline, indem Sie Speichern auswählen, und committen Sie sie direkt im Mainbranch.

Bereitstellen einer stabilen Version

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

Für die erste Ausführung der Pipeline sind die stabile Version der Workloads und ihre Baseline- oder Canary-Versionen nicht im Cluster vorhanden. So stellen Sie die stabile Version bereit

  1. Ändern Sie success_rate = 5 in app/app.py in success_rate = 10. Diese Änderung löst die Pipeline aus, was zu einem Build und Push des Images in die Containerregistrierung führt. Außerdem wird die Phase DeployCanary ausgelöst.
  2. Da Sie eine Genehmigung für die akspromote-Umgebung konfiguriert haben, wartet das Release, ehe diese Phase ausgeführt wird.
  3. Wählen Sie in der Zusammenfassung der Ausführung Überprüfen>Genehmigen aus. Dadurch wird die stabile Version der Workloads (die sampleapp-Bereitstellung in manifests/deployment.yml) im Namespace bereitgestellt.

Einleiten des Canary-Workflows

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

Ändern Sie success_rate = 10 in app/app.py in success_rate = 20.

Diese Änderung löst die Buildpipeline aus, was zum Build und Push des Images in die Containerregistrierung führt. Dieser Prozess löst wiederum die Releasepipeline aus und startet die Phase Canary bereitstellen.

Simulieren von Anforderungen

Führen Sie auf Ihrem Entwicklungscomputer die folgenden Befehle aus, und sorgen Sie dafür, dass ein konstanter Datenstrom von Anforderungen an den sampleapp-Dienst gesendet wird. sampleapp leitet die Anforderungen an die Pods weiter, die von der stabilen sampleapp Bereitstellung ausgeführt werden, und an die Pods, die von den sampleapp-baseline- und sampleapp-canary-Bereitstellungen ausgeführt werden. Der für sampleapp angegebene Selektor gilt für alle diese Pods.

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/

Einrichten des Grafana-Dashboards

  1. Führen Sie auf Ihrem lokalen Entwicklungscomputer den folgenden Befehl zur Portweiterleitung aus, um auf Grafana zugreifen zu können.

    kubectl port-forward svc/sampleapp-grafana 3000:80
    
  2. Öffnen Sie in einem Browser die folgende URL.

    http://localhost:3000/login
    
  3. Wenn Sie zur Eingabe von Anmeldeinformationen aufgefordert werden, können Sie die folgenden Werte verwenden, es sei denn, der Wert adminPassword wurde während der Installation des Helm-Diagramms für prometheus-operator überschrieben:

    • Benutzername: admin
    • Kennwort: prom-operator
  4. Wählen Sie im Menü auf der linken Seite +>Dashboard>Graph aus.

  5. Wählen Sie eine beliebige Stelle im neu hinzugefügten Bereich aus, und geben Sie e ein, um den Bereich zu bearbeiten.

  6. Geben Sie auf der Registerkarte Metriken die folgende Abfrage ein:

    rate(requests_total{pod=~"sampleapp-.*", custom_status="good"}[1m])
    
  7. Ändern Sie auf der Registerkarte Allgemein den Namen dieses Bereichs in Alle Beispiel-App-Pods.

  8. Ändern Sie auf der Übersichtsleiste oben auf der Seite den Bereich „Dauer“ in Letzte 5 Minuten oder Letzte 15 Minuten.

  9. Wählen Sie zum Speichern dieses Bereichs auf der Übersichtsleiste das Symbol „Speichern“ aus.

  10. Im vorherigen Bereich werden Erfolgsquotenmetriken aus allen Varianten visualisiert. Dazu gehören „Stabil“ (aus der sampleapp-Bereitstellung), „Baseline“ (aus der sampleapp-baseline-Bereitstellung) und „Canary“ (aus der sampleapp-canary-Bereitstellung). Sie können ausschließlich die Baseline- und Canary-Metriken visualisieren, indem Sie einen weiteren Bereich mit der folgenden Konfiguration hinzufügen:

    • Wählen Sie auf der Registerkarte Allgemein unter Titel die Option Baseline und Canary für Beispiel-App aus.
    • Geben Sie auf der Registerkarte Metriken die folgende Abfrage ein:
    rate(requests_total{pod=~"sampleapp-baseline-.*|sampleapp-canary-.*", custom_status="good"}[1m])
    

    Hinweis

    Im Bereich für Baseline- und Canary-Metriken sind die Metriken nur unter bestimmten Bedingungen zum Vergleichen verfügbar. Diese Bedingungen liegen vor, wenn die Phase „Canary bereitstellen“ erfolgreich abgeschlossen wurde und die Canary-Phase „Höherstufen/Ablehnen“ auf einen manuellen Eingriff wartet.

    Tipp

    Richten Sie Anmerkungen für Grafana-Dashboards ein, um Phasenabschlussereignisse für Canary bereitstellen und Canary höherstufen/ablehnen visuell darzustellen. Dies ist hilfreich, damit Sie wissen, wann Sie mit dem Vergleich zwischen Baseline und Canary beginnen und wann das Höherstufen bzw. Ablehnen des Canarys abgeschlossen ist.

Vergleichen von Baseline und Canary

  1. An diesem Punkt wurde die Phase Canary bereitstellen erfolgreich abgeschlossen (basierend auf der Änderung von success_rate von 10 in 20). Die Phase Canary höherstufen/ablehnen wartet auf einen manuellen Eingriff. Sie können jetzt im Grafana-Dashboard die Erfolgsquote (gemäß custom_status=good) der Baseline- und Canary-Varianten vergleichen. Es sollte ungefähr wie folgt aussehen:

    Screenshot that shows a comparison of baseline and canary metrics.

  2. Basierend auf der Beobachtung, dass die Erfolgsquote für Canary höher ist, stufen Sie den Canary höher. Wählen Sie in der Aufgabe für manuellen Eingriff Fortsetzen aus.