Partager via


Tutoriel : Utiliser une stratégie de déploiement canary pour Kubernetes

Azure DevOps Services | Azure DevOps Server 2022

Ce guide étape par étape couvre comment utiliser la tâche Kubernetes manifest avec la stratégie canary. Une stratégie de déploiement canary déploie de nouvelles versions d’une application à côté des versions stables en production.

Vous utilisez le workflow associé pour déployer le code et comparer les déploiements de l'application de référence et de l'application canari. En fonction de l’évaluation, vous décidez de promouvoir ou de rejeter le déploiement canary.

Ce tutoriel utilise les connexions au registre Docker et au service Azure Resource Manager pour se connecter aux ressources Azure. Pour un cluster privé Azure Kubernetes Service (AKS) ou un cluster avec des comptes locaux désactivés, une connexion de service Azure Resource Manager est une meilleure solution de connexion.

Prérequis

Fichiers du référentiel GitHub

Le référentiel GitHub contient les fichiers suivants :

Fichier Description
./app/app.py Un serveur Web simple, basé sur Flask . Le fichier configure un compteur personnalisé pour le nombre de réponses correctes et incorrectes, basé sur la valeur de la variable success_rate.
./app/Dockerfile Utilisé pour construire l’image à chaque modification de app.py. Chaque modification déclenche le pipeline de build pour construire l’image et la pousser vers le référentiel de conteneurs.
./manifests/deployment.yml Contient la spécification de la charge de travail de déploiement sampleapp correspondant à l’image publiée. Vous utilisez ce fichier manifeste pour la version stable de l’objet de déploiement et pour dériver les variantes de base et canary des charges de travail.
./manifests/service.yml Crée le service sampleapp. Ce service redirige les requêtes vers les pods créés par les déploiements stables, de base et canary.
./misc/fortio.yml Configure un déploiement fortio. Ce déploiement est un outil de test de charge qui envoie un flux de requêtes au service sampleapp déployé. Le flux de requêtes est redirigé vers les pods sous les trois déploiements : stable, de base et canary.

Création de connexions de service

  1. Dans votre projet Azure DevOps, allez dans Paramètres du projet>Pipelines>Connexions de service.
  2. Créez une connexion de service Docker Registry nommée azure-pipelines-canary-acr associée à votre instance Azure Container Registry.
  3. Créez une connexion au service Azure Resource Manager avec une identité de charge de travail nommée azure-pipelines-canary-k8s pour votre groupe de ressources.

Ajouter l’étape de génération

  1. Dans votre projet Azure DevOps, allez dans Pipelines>Créer un pipeline ou Nouveau pipeline.

  2. Sélectionnez GitHub comme emplacement de votre code et sélectionnez votre référentiel forké azure-pipelines-canary-k8s.

  3. Sous l’onglet Configurer, choisissez Pipeline de démarrage.

  4. Dans l’onglet Revue, remplacez le fichier YAML du pipeline par le code suivant.

    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)
    

    Si la connexion de service Docker Registry que vous avez créée est associée à un référentiel de conteneurs nommé example.azurecr.io, l’image est définie sur example.azurecr.io/azure-pipelines-canary-k8s:$(Build.BuildId).

  5. Sélectionnez Enregistrer et exécuter et assurez-vous que le travail s’exécute avec succès.

Modifier le fichier manifeste

Dans votre fork de référentiel, modifiez manifests/deployment.yml pour remplacer <foobar> par l’URL de votre référentiel de conteneurs, par exemple example.azurecr.io/azure-pipelines-canary-k8s.

Configurer un déploiement continu

Configurez maintenant le déploiement continu, déployez la phase canary, et promouvez ou rejetez le canary via une approbation manuelle.

Créer un environnement

Vous pouvez effectuer un déploiement avec YAML ou Classic.

  1. Dans votre projet Azure DevOps, allez dans Pipelines>Environnements puis sélectionnez Créer un environnement ou Nouvel environnement.
  2. Sur le premier écran Nouvel environnement, entrez akscanary sous Nom, sélectionnez Kubernetes sous Ressource, puis sélectionnez Suivant.
  3. Remplissez l’écran Ressource Kubernetes comme suit :
    • Fournisseur : Sélectionnez Azure Kubernetes Service.
    • Abonnement Azure : Sélectionnez votre abonnement Azure.
    • Cluster : sélectionnez votre cluster AKS.
    • Espace de noms : Sélectionnez Nouveau et entrez canarydemo.
  4. Sélectionnez Valider et créer.

Ajouter la phase canary

  1. Allez dans Pipelines, sélectionnez le pipeline que vous avez créé, et sélectionnez Modifier.

  2. Remplacez l’intégralité du fichier YAML du pipeline par le code suivant.

    Ce code modifie l’étape Docker@2 que vous avez exécutée précédemment pour utiliser une phase, et ajoute deux étapes supplémentaires pour copier les répertoires manifests et misc en tant qu’artefacts pour les étapes consécutives.

    Le code déplace également certaines valeurs vers des variables pour une utilisation plus facile ultérieurement dans le pipeline. Dans la variable containerRegistry, remplacez <example> par le nom de votre référentiel de conteneurs.

    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. Ajoutez une autre phase à la fin du fichier YAML pour déployer la version canary. Remplacez les valeurs my-resource-group et my-aks-cluster par votre groupe de ressources et le nom de votre 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. Sélectionnez Valider et enregistrer, et enregistrez le pipeline directement dans la branche principale.

Ajoutez une approbation manuelle pour promouvoir ou rejeter le déploiement de canaris

Vous pouvez intervenir manuellement avec YAML ou Classic.

  1. Créez un nouvel environnement Kubernetes appelé akspromote.
  2. Ouvrez le nouvel environnement akspromote depuis la liste des environnements, et sélectionnez Approbations dans l’onglet Approbations et vérifications.
  3. Sur l’écran Approbations, ajoutez votre propre compte utilisateur sous Approbateurs.
  4. Développez Avancé, et assurez-vous que Autoriser les approbateurs à approuver leurs propres exécutions est sélectionné.
  5. Sélectionnez Créer.

Ajouter des phases de promotion et de rejet au pipeline

  1. Allez dans Pipelines, sélectionnez le pipeline que vous avez créé, et sélectionnez Modifier.

  2. Ajoutez la phase PromoteRejectCanary suivante à la fin de votre fichier YAML qui promeut les modifications.

    - 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. Ajoutez la phase RejectCanary suivante à la fin du fichier qui annule les modifications.

    - 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. Sélectionnez Valider et enregistrer, et enregistrez le pipeline directement dans la branche principale.

Déployer une version stable

Pour la première exécution du pipeline, la version stable des charges de travail et leurs versions basées ou canary n’existent pas dans le cluster. Déployez une version stable de la charge de travail sampleapp comme suit.

Vous pouvez déployer une version stable avec YAML ou Classic.

  1. Dans app/app.py, remplacez success_rate = 50 par success_rate = 100. Ce changement déclenche le pipeline, construit et pousse l’image vers le référentiel de conteneurs, et déclenche également la phase DeployCanary.
  2. Étant donné que vous avez configuré une approbation sur l’environnement akspromote, la publication attend avant d’exécuter cette phase. Sur la page de résumé de l’exécution du build, sélectionnez Revue puis sélectionnez Approuver.

Une fois approuvé, le pipeline déploie la version stable de la charge de travail sampleapp dans manifests/deployment.yml vers l’espace de noms.

Lancez le workflow canarien et rejetez l'approbation.

La version stable de la charge de travail sampleapp existe maintenant dans le cluster. Ensuite, apportez la modification suivante à l'application de simulation.

  1. Dans app/app.py, remplacez success_rate = 50 par success_rate = 100. Ce changement déclenche le pipeline, construit et pousse l’image vers le référentiel de conteneurs, et déclenche également la phase DeployCanary.
  2. Étant donné que vous avez configuré une approbation sur l’environnement akspromote, la publication attend avant d’exécuter cette phase.
  3. Sur la page de résumé de l'exécution de la construction, sélectionnez Examiner, puis Rejeter dans la boîte de dialogue qui s'affiche. Cela rejette le déploiement.

Une fois rejeté, le pipeline empêche le déploiement du code.

Nettoyage

Si vous ne comptez pas continuer à utiliser cette application, supprimez le groupe de ressources dans Azure portal et le projet dans Azure DevOps