Partager via


Travaux de déploiement

Azure DevOps Services | Azure DevOps Server | Azure DevOps Server 2022

Importante

  • Les noms de travaux et d’étape ne doivent pas entrer en conflit avec des mots clés réservés (par deployment exemple, pour le type de travail)
  • Chaque tâche d’une étape doit avoir un nom unique.

Dans les pipelines YAML, nous vous recommandons de placer vos étapes de déploiement dans un type de tâche spécial appelé tâche de déploiement. Un travail de déploiement est une collection d’étapes qui sont exécutées séquentiellement sur l’environnement. Une tâche de déploiement et une tâche traditionnelle peuvent exister dans la même étape. Azure DevOps prend en charge les stratégies runOnce, rolling et canary.

Les travaux de déploiement offrent les avantages suivants :

  • Historique du déploiement : vous obtenez l’historique du déploiement dans tous les pipelines, jusqu’à une ressource spécifique et l’état des déploiements à des fins d’audit.
  • Appliquer une stratégie de déploiement : vous définissez comment votre application est déployée.

Un travail de déploiement ne clone pas automatiquement le dépôt source. Vous pouvez consulter le dépôt source dans votre travail avec checkout: self.

Note

Cet article se concentre sur le déploiement avec des tâches de déploiement. Pour apprendre à déployer sur Azure avec des pipelines, consultez la page Présentation du déploiement sur Azure.

schéma

Accédez au schéma YAML pour afficher les définitions jobs.deployment et jobs.deployment.environment .

Pour les machines virtuelles, vous n’avez pas besoin de définir un pool. Toutes les étapes que vous définissez dans un travail de déploiement avec une ressource de machine virtuelle s’exécutent sur cette machine virtuelle et non sur l’agent dans le pool. Pour d’autres types de ressources, tels que Kubernetes, vous devez définir un pool afin que les tâches puissent s’exécuter sur cette machine.

Stratégies de déploiement

Lorsque vous déployez des mises à jour d’application, il est important que la technique que vous utilisez pour fournir la mise à jour :

  • Activez l’initialisation.
  • Déployez la mise à jour.
  • Routez le trafic vers la version mise à jour.
  • Testez la version mise à jour après le routage du trafic.
  • En cas d’échec, exécutez les étapes pour restaurer la dernière version connue.

Pour ce faire, nous utilisons des hooks de cycle de vie qui peuvent exécuter des étapes pendant le déploiement. Chacun des hooks de cycle de vie se résout en une tâche d’agent ou une tâche de serveur (ou une tâche de conteneur ou de validation à l’avenir), en fonction de l’attribut pool. Par défaut, les hooks de cycle de vie héritent du pool spécifié par la tâche deployment.

Les travaux de déploiement utilisent la variable système $(Pipeline.Workspace).

Descriptions des hooks de cycle de vie

preDeploy : utilisé pour exécuter des étapes qui initialisent les ressources avant le début du déploiement de l’application.

deploy : utilisé pour exécuter les étapes qui déploient votre application. La tâche de téléchargement d’artefact est automatiquement injectée uniquement dans le hook deploy pour les tâches de déploiement. Pour arrêter le téléchargement des artefacts, utilisez - download: none ou choisissez les artefacts spécifiques à télécharger en spécifiant la tâche Télécharger l’artefact de pipeline.

routeTraffic : utilisé pour exécuter les étapes qui servent le trafic vers la version mise à jour.

postRouteTraffic : utilisé pour exécuter les étapes après le routage du trafic. En règle générale, ces tâches surveillent l’intégrité de la version mise à jour pendant un intervalle défini.

on: failure ou on: success : utilisé pour exécuter les étapes des actions de restauration ou de nettoyage.

Stratégie de déploiement RunOnce

runOnce est la stratégie de déploiement la plus simple où tous les hooks de cycle de vie, à savoir preDeploydeploy, routeTrafficet postRouteTraffic, sont exécutés une seule fois. Ensuite, on:success ou on:failure est exécuté.

strategy: 
    runOnce:
      preDeploy:        
        pool: [ server | pool ] # See pool schema.        
        steps:
        - script: [ script | bash | pwsh | powershell | checkout | task | templateReference ]
      deploy:          
        pool: [ server | pool ] # See pool schema.        
        steps:
        ...
      routeTraffic:         
        pool: [ server | pool ]         
        steps:
        ...        
      postRouteTraffic:          
        pool: [ server | pool ]        
        steps:
        ...
      on:
        failure:         
          pool: [ server | pool ]           
          steps:
          ...
        success:          
          pool: [ server | pool ]           
          steps:
          ...

Si vous utilisez des agents auto-hébergés, vous pouvez utiliser les options de nettoyage de l’espace de travail pour nettoyer votre espace de travail de déploiement.

  jobs:
  - deployment: MyDeploy
    pool:
      vmImage: 'ubuntu-latest'
    workspace:
      clean: all
    environment: staging

Stratégie de déploiement propagé

Un déploiement propagé remplace les instances de la version précédente d’une application par des instances de la nouvelle version de l’application sur un ensemble fixe de machines virtuelles (jeu propagé) dans chaque itération.

Nous ne prenons actuellement en charge que la stratégie de déploiement progressif pour les ressources de machine virtuelle.

Par exemple, un déploiement progressif attend généralement que les déploiements sur chaque ensemble de machines virtuelles soient terminés avant de passer à l’ensemble suivant. Vous pouvez effectuer un contrôle d’intégrité après chaque itération et, si un problème important survient, le déploiement progressif peut être arrêté.

Les déploiements progressifs peuvent être configurés en spécifiant le mot-clé rolling: sous le nœud strategy:. La variable strategy.name est disponible dans ce bloc de stratégie, qui prend le nom de la stratégie. Dans ce cas, rolling.

strategy:
  rolling:
    maxParallel: [ number or percentage as x% ]
    preDeploy:        
      steps:
      - script: [ script | bash | pwsh | powershell | checkout | task | templateReference ]
    deploy:          
      steps:
      ...
    routeTraffic:         
      steps:
      ...        
    postRouteTraffic:          
      steps:
      ...
    on:
      failure:         
        steps:
        ...
      success:          
        steps:
        ...

Tous les hooks de cycle de vie sont pris en charge et des tâches de hook de cycle de vie sont créées pour s’exécuter sur chaque machine virtuelle.

preDeploy, deploy, routeTraffic et postRouteTraffic sont exécutés une fois par taille de lot définie par maxParallel. Ensuite, on: success ou on: failure est exécuté.

Avec maxParallel: <# or % of VMs>, vous pouvez contrôler le nombre/pourcentage de machines virtuelles cibles à déployer en parallèle. Cela garantit que l’application s’exécute sur ces machines et est capable de traiter les requêtes pendant que le déploiement est en cours sur les autres machines, ce qui réduit le temps d’indisponibilité global.

Note

Cette fonctionnalité présente quelques lacunes connues. Par exemple, lorsque vous réessayez une étape, il réexécute le déploiement sur toutes les machines virtuelles, pas seulement les cibles ayant échoué.

Stratégie de déploiement avec contrôle de validité

La stratégie de déploiement Canary est une stratégie de déploiement avancée qui permet d’atténuer le risque impliqué dans le déploiement de nouvelles versions d’applications. En utilisant cette stratégie, vous pouvez d’abord déployer les changements sur un petit sous-ensemble de serveurs. Quand la nouvelle version vous semble fiable, vous pouvez la publier sur davantage de serveurs de votre infrastructure et lui envoyer plus de trafic.

strategy: 
    canary:
      increments: [ number ]
      preDeploy:        
        pool: [ server | pool ] # See pool schema.        
        steps:
        - script: [ script | bash | pwsh | powershell | checkout | task | templateReference ]
      deploy:          
        pool: [ server | pool ] # See pool schema.        
        steps:
        ...
      routeTraffic:         
        pool: [ server | pool ]         
        steps:
        ...        
      postRouteTraffic:          
        pool: [ server | pool ]        
        steps:
        ...
      on:
        failure:         
          pool: [ server | pool ]           
          steps:
          ...
        success:          
          pool: [ server | pool ]           
          steps:
          ...

La stratégie de déploiement Canary prend en charge le hook de cycle de vie preDeploy (exécuté une fois) et itère avec les hooks de cycle de vie deploy, routeTraffic et postRouteTraffic. Elle se termine ensuite avec le hook success ou failure.

Les variables suivantes sont disponibles dans cette stratégie :

strategy.name : nom de la stratégie. Par exemple, canary.
strategy.action : action à effectuer sur le cluster Kubernetes. Par exemple, deploy, promote ou reject.
strategy.increment : valeur d’incrément utilisée dans l’interaction en cours. Cette variable est disponible uniquement dans les hooks de cycle de vie deploy, routeTraffic et postRouteTraffic.

Exemples

Stratégie de déploiement RunOnce

L’extrait YAML suivant illustre une utilisation simple d’un travail de déploiement à l’aide de la stratégie de déploiement runOnce. L’exemple inclut une étape de vérification.

jobs:
  # Track deployments on the environment.
  - deployment: DeployWeb
    displayName: deploy Web App
    pool:
      vmImage: 'ubuntu-latest'
    # Creates an environment if it doesn't exist.
    environment: 'smarthotel-dev'
    strategy:
      # Default deployment strategy, more coming...
      runOnce:
        deploy:
          steps:
            - checkout: self
            - script: echo my first deployment

À chaque exécution de ce travail, l’historique du déploiement est enregistré dans l’environnement smarthotel-dev.

Note

  • Il est également possible de créer un environnement avec des ressources vides et de l’utiliser comme interpréteur de commande abstrait pour enregistrer l’historique du déploiement, comme le montre l’exemple précédent.

L’exemple suivant montre comment un pipeline peut référencer à la fois un environnement et une ressource à utiliser comme cible pour une tâche de déploiement.

jobs:
  - deployment: DeployWeb
    displayName: deploy Web App
    pool:
      vmImage: 'ubuntu-latest'
    # Records deployment against bookings resource - Kubernetes namespace.
    environment: 'smarthotel-dev.bookings'
    strategy: 
      runOnce:
        deploy:
          steps:
            # No need to explicitly pass the connection details.
            - task: KubernetesManifest@1
              displayName: Deploy to Kubernetes cluster
              inputs:
                action: deploy
                namespace: $(k8sNamespace)
                manifests: |
                  $(System.ArtifactsDirectory)/manifests/*
                imagePullSecrets: |
                  $(imagePullSecret)
                containers: |
                  $(containerRegistry)/$(imageRepository):$(tag)

Cette approche offre les avantages suivants :

  • Enregistre l’historique du déploiement sur une ressource spécifique dans l’environnement, plutôt que d’enregistrer l’historique sur toutes les ressources de l’environnement.
  • Les étapes de la tâche de déploiement héritent automatiquement des détails de connexion de la ressource (dans ce cas, un espace de noms Kubernetes, smarthotel-dev.bookings), car la tâche de déploiement est liée à l’environnement. Ceci est utile dans les cas où les mêmes détails de connexion sont définis pour plusieurs étapes de la tâche.

Note

Si vous utilisez un cluster AKS privé, vérifiez que vous êtes connecté au réseau virtuel du cluster, car le point de terminaison du serveur d’API n’est pas exposé via une adresse IP publique.

Azure Pipelines recommande de configurer un agent auto-hébergé dans un réseau virtuel ayant accès au réseau virtuel du cluster. Pour plus d’informations, consultez Options de connexion au cluster privé.

Stratégie de déploiement propagé

La stratégie de déploiement progressif pour les machines virtuelles met à jour jusqu’à cinq cibles à chaque itération. maxParallel détermine le nombre de cibles qui peuvent être déployées en parallèle. La sélection prend en compte le nombre absolu ou le pourcentage de cibles qui doivent rester disponibles à tout moment, à l’exclusion des cibles sur lesquelles un déploiement est en cours. Il est également utilisé pour déterminer les conditions de réussite et d’échec pendant le déploiement.

jobs:
  - deployment: VMDeploy
    displayName: web
    environment:
      name: smarthotel-dev
      resourceType: VirtualMachine
    strategy:
      rolling:
        maxParallel: 5  # for percentages, mention as x%
        preDeploy:
          steps:
            - download: current
              artifact: drop
            - script: echo initialize, cleanup, backup, install certs
        deploy:
          steps:
            - task: IISWebAppDeploymentOnMachineGroup@0
              displayName: 'Deploy application to Website'
              inputs:
                WebSiteName: 'Default Web Site'
                Package: '$(Pipeline.Workspace)/drop/**/*.zip'
        routeTraffic:
          steps:
            - script: echo routing traffic
        postRouteTraffic:
          steps:
            - script: echo health check post-route traffic
        on:
          failure:
            steps:
              - script: echo Restore from backup! This is on failure
          success:
            steps:
              - script: echo Notify! This is on success

Stratégie de déploiement avec contrôle de validité

Dans l’exemple suivant, la stratégie Canary pour AKS déploie d’abord les modifications sur 10 % des pods, puis sur 20 %, tout en surveillant l’intégrité pendant postRouteTraffic. Si tout se passe bien, elle passe à 100 %.

jobs:
  - deployment: 
      environment: smarthotel-dev.bookings
      pool: 
        name: smarthotel-devPool
      strategy:                  
        canary:      
          increments: [10, 20]  
          preDeploy:                                     
            steps:           
              - script: initialize, cleanup....
          deploy:             
            steps: 
              - script: echo deploy updates...
              - task: KubernetesManifest@1
                inputs:
                  action: $(strategy.action)
                  namespace: 'default'
                  strategy: $(strategy.name)
                  percentage: $(strategy.increment)
                  manifests: 'manifest.yml'
          postRouteTraffic: 
            pool: server 
            steps:           
              - script: echo monitor application health...
          on: 
            failure: 
              steps: 
                - script: echo clean-up, rollback...
            success: 
              steps: 
                - script: echo checks passed, notify...

Utilisez des décorateurs de pipeline pour injecter automatiquement des étapes

Les décorateurs de pipeline peuvent être utilisés dans les tâches de déploiement pour injecter automatiquement toute étape personnalisée (par exemple, un scanner de vulnérabilité) à chaque exécution de hook de cycle de vie de chaque tâche de déploiement. Étant donné que les décorateurs de pipeline peuvent être appliqués à tous les pipelines d’une organisation, cela peut être utilisé dans le cadre de la mise en œuvre de pratiques de déploiement sécurisées.

En outre, les tâches de déploiement peuvent être exécutées en tant que tâches de conteneur avec des services side-car, si ceux-ci sont définis.

Prise en charge des variables de sortie

Définissez des variables de sortie dans les hooks du cycle de vie d’une tâche de déploiement et utilisez-les dans d’autres étapes et tâches en aval au sein de la même étape.

Pour partager des variables entre les étapes, générez un artefact dans une étape, puis utilisez-le dans une étape suivante, ou utilisez la syntaxe stageDependencies décrite dans variables.

Lors de l’exécution de stratégies de déploiement, vous pouvez accéder aux variables de sortie entre les tâches à l’aide de la syntaxe suivante.

  • Pour la stratégie runOnce : $[dependencies.<job-name>.outputs['<job-name>.<step-name>.<variable-name>']] (par exemple, $[dependencies.JobA.outputs['JobA.StepA.VariableA']])
  • Pour la stratégie runOnce plus un type de ressource : $[dependencies.<job-name>.outputs['Deploy_<resource-name>.<step-name>.<variable-name>']]. (Par exemple, $[dependencies.JobA.outputs['Deploy_VM1.StepA.VariableA']])
  • Pour la stratégie canary : $[dependencies.<job-name>.outputs['<lifecycle-hookname>_<increment-value>.<step-name>.<variable-name>']]
  • Pour la stratégie rolling : $[dependencies.<job-name>.outputs['<lifecycle-hookname>_<resource-name>.<step-name>.<variable-name>']]
# Set an output variable in a lifecycle hook of a deployment job executing canary strategy.
- deployment: A
  pool:
    vmImage: 'ubuntu-latest'
  environment: staging
  strategy:                  
    canary:      
      increments: [10,20]  # Creates multiple jobs, one for each increment. Output variable can be referenced with this.
      deploy:
        steps:
        - bash: echo "##vso[task.setvariable variable=myOutputVar;isOutput=true]this is the deployment variable value"
          name: setvarStep
        - bash: echo $(setvarStep.myOutputVar)
          name: echovar

# Map the variable from the job.
- job: B
  dependsOn: A
  pool:
    vmImage: 'ubuntu-latest'
  variables:
    myVarFromDeploymentJob: $[ dependencies.A.outputs['deploy_10.setvarStep.myOutputVar'] ]
  steps:
  - script: "echo $(myVarFromDeploymentJob)"
    name: echovar

Pour une tâche runOnce, spécifiez le nom de la tâche au lieu du hook de cycle de vie :

# Set an output variable in a lifecycle hook of a deployment job executing runOnce strategy.
- deployment: A
  pool:
    vmImage: 'ubuntu-latest'
  environment: staging
  strategy:                  
    runOnce:
      deploy:
        steps:
        - bash: echo "##vso[task.setvariable variable=myOutputVar;isOutput=true]this is the deployment variable value"
          name: setvarStep
        - bash: echo $(setvarStep.myOutputVar)
          name: echovar

# Map the variable from the job.
- job: B
  dependsOn: A
  pool:
    vmImage: 'ubuntu-latest'
  variables:
    myVarFromDeploymentJob: $[ dependencies.A.outputs['A.setvarStep.myOutputVar'] ]
  steps:
  - script: "echo $(myVarFromDeploymentJob)"
    name: echovar

Lorsque vous définissez un environnement dans une tâche de déploiement, la syntaxe de la variable de sortie varie en fonction de la manière dont l’environnement est défini. Dans cet exemple, env1 utilise une notation abrégée et env2 inclut la syntaxe complète avec un type de ressource défini.

stages:
- stage: StageA
  jobs:
  - deployment: A1
    pool:
      vmImage: 'ubuntu-latest'
    environment: env1
    strategy:                  
      runOnce:
        deploy:
          steps:
          - bash: echo "##vso[task.setvariable variable=myOutputVar;isOutput=true]this is the deployment variable value"
            name: setvarStep
          - bash: echo $(System.JobName)
  - deployment: A2
    pool:
      vmImage: 'ubuntu-latest'
    environment: 
      name: env2
      resourceName: vmsfortesting
      resourceType: virtualmachine
    strategy:                  
      runOnce:
        deploy:
          steps:
          - script: echo "##vso[task.setvariable variable=myOutputVarTwo;isOutput=true]this is the second deployment variable value"
            name: setvarStepTwo
  
  - job: B1
    dependsOn: A1
    pool:
      vmImage: 'ubuntu-latest'
    variables:
      myVarFromDeploymentJob: $[ dependencies.A1.outputs['A1.setvarStep.myOutputVar'] ]
      
    steps:
    - script: "echo $(myVarFromDeploymentJob)"
      name: echovar
 
  - job: B2
    dependsOn: A2
    pool:
      vmImage: 'ubuntu-latest'
    variables:
      myVarFromDeploymentJob: $[ dependencies.A2.outputs['A2.setvarStepTwo.myOutputVarTwo'] ]
      myOutputVarTwo: $[ dependencies.A2.outputs['Deploy_vmsfortesting.setvarStepTwo.myOutputVarTwo'] ]
    
    steps:
    - script: "echo $(myOutputVarTwo)"
      name: echovartwo

Lorsque vous générez une variable à partir d’une tâche dans la première étape, la référence à cette variable à partir d’une tâche de déploiement dans l’étape suivante utilise une syntaxe différente selon que vous souhaitez définir une variable ou l’utiliser comme condition pour l’étape.

stages:
- stage: StageA
  jobs:
  - job: A1
    steps:
      - pwsh: echo "##vso[task.setvariable variable=RunStageB;isOutput=true]true"
        name: setvarStep
      - bash: echo $(System.JobName)

- stage: StageB
  dependsOn: 
    - StageA
 
  # when referring to another stage, stage name is included in variable path
  condition: eq(dependencies.StageA.outputs['A1.setvarStep.RunStageB'], 'true')
  
  # Variables reference syntax differs slightly from inter-stage condition syntax
  variables:
    myOutputVar: $[stageDependencies.StageA.A1.outputs['setvarStep.RunStageB']]
  jobs:
  - deployment: B1
    pool:
      vmImage: 'ubuntu-latest'
    environment: envB
    strategy:                  
      runOnce:
        deploy:
          steps:
          - bash: echo $(myOutputVar)

Lorsque vous générez une variable à partir d’une tâche de déploiement, utilisez la syntaxe stageDependencies pour la référencer à partir de l’étape suivante (par exemple, $[stageDependencies.<stage-name>.<job-name>.outputs[Deploy_<resource-name>.<step-name>.<variable-name>]]).

stages:
- stage: StageA
  jobs:
    - deployment: A1
      environment: 
        name:  env1
        resourceName: DevEnvironmentV
        resourceType: virtualMachine
      strategy:
        runOnce:
          deploy:
            steps:
              - script: echo "##vso[task.setvariable variable=myVar;isOutput=true]true"
                name: setvarStep
              - script: |
                  echo "Value of myVar in the same Job : $(setVarStep.myVar)"
                displayName: 'Verify variable in StageA'
- stage: StageB
  dependsOn: StageA

  # Full Variables syntax for inter-stage jobs
  variables:
    myOutputVar: $[stageDependencies.StageA.A1.outputs['Deploy_DevEnvironmentV.setvarStep.myVar']]
  jobs:
  - deployment: B1
    pool:
      vmImage: 'ubuntu-latest'
    environment: envB
    strategy:                  
      runOnce:
        deploy:
          steps:
          - bash: echo $(myOutputVar)

En savoir plus sur la définition d’une variable de sortie multi-tâches

Questions fréquentes (FAQ)

Mon pipeline est bloqué avec le message « Tâche en attente... ». Comment puis-je résoudre ce problème ?

Cela peut se produire lorsqu’il existe un conflit de noms entre deux tâches. Vérifiez que toutes les tâches de déploiement de la même étape ont un nom unique et que les noms des tâches et des étapes ne contiennent pas de mots-clés. Si le renommage ne résout pas le problème, consultez la section Dépannage des exécutions de pipeline.

Les décorateurs sont-ils pris en charge dans les groupes de déploiement ?

Non. Vous ne pouvez pas utiliser de décorateurs dans les groupes de déploiement.