Travaux de déploiement
Azure DevOps Services | Azure DevOps Server 2022 | Azure DevOps Server 2020
Important
- Les noms de travail et d’index ne peuvent pas contenir de mots clés (exemple :
deployment
). - Chaque travail inclus dans un index doit porter un nom unique.
Dans les pipelines YAML, nous vous recommandons de placer vos étapes de déploiement dans un travail de type spécial appelée travail de déploiement. Un travail de déploiement est une collection d’étapes qui sont exécutées séquentiellement sur l’environnement. Un travail de déploiement et un travail traditionnel peuvent exister dans le même index. Azure DevOps prend en charge les stratégies de déploiement runOnce, propagé et avec contrôle de validité.
Les travaux de déploiement offrent les avantages suivants :
- Historique de déploiement : vous obtenez l’historique de déploiement entre les pipelines, jusqu’à une ressource et un état spécifiques des déploiements pour l’audit.
- Appliquer une stratégie de déploiement : vous définissez la façon dont votre application est déployée.
Un travail de déploiement ne clone pas automatiquement le dépôt source. Vous pouvez extraire le dépôt source au sein de votre travail avec checkout: self
.
Notes
Cet article se concentre sur le déploiement à l’aide de travaux de déploiement. Pour découvrir comment déployer sur Azure avec des pipelines, consultez Vue d’ensemble du déploiement sur Azure.
schéma
Voici la syntaxe complète permettant de spécifier un travail de déploiement :
jobs:
- deployment: string # name of the deployment job, A-Z, a-z, 0-9, and underscore. The word "deploy" is a keyword and is unsupported as the deployment name.
displayName: string # friendly name to display in the UI
pool: # not required for virtual machine resources
name: string # Use only global level variables for defining a pool name. Stage/job level variables are not supported to define pool name.
demands: string | [ string ]
workspace:
clean: outputs | resources | all # what to clean up before the job runs
dependsOn: string
condition: string
continueOnError: boolean # 'true' if future jobs should run even if this job fails; defaults to 'false'
container: containerReference # container to run this job inside
services: { string: string | container } # container resources to run as a service container
timeoutInMinutes: nonEmptyString # how long to run the job before automatically cancelling
cancelTimeoutInMinutes: nonEmptyString # how much time to give 'run always even if cancelled tasks' before killing them
variables: # several syntaxes, see specific section
environment: string # target environment name and optionally a resource name to record the deployment history; format: <environment-name>.<resource-name>
strategy:
runOnce: #rolling, canary are the other strategies that are supported
deploy:
steps: [ script | bash | pwsh | powershell | checkout | task | templateReference ]
Il existe une autre syntaxe plus précise que vous pouvez également utiliser pour la propriété environment
.
environment:
name: string # Name of environment.
resourceName: string # Name of resource.
resourceId: string # Id of resource.
resourceType: string # Type of environment resource.
tags: string # List of tag filters.
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, comme Kubernetes, vous avez besoin de 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 distribuer la mise à jour vous permette d’effectuer ceci :
- 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 de restauration de la dernière bonne version connue.
Pour cela, 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 travail d’agent ou travail de serveur (prochainement en travail de conteneur ou de validation), en fonction de l’attribut pool
. Par défaut, les hooks de cycle de vie héritent du pool
spécifié par le travail 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 les étapes qui initialisent les ressources avant le démarrage 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 des artefacts est injectée automatiquement uniquement dans le hook deploy
pour les travaux de déploiement. Pour arrêter le téléchargement d’artefacts, utilisez - download: none
ou choisissez des artefacts spécifiques à télécharger en spécifiant la tâche Télécharger un artefact de pipeline.
routeTraffic
: Utilisé pour exécuter les étapes qui servent le trafic à 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 supervisent l’intégrité de la version mise à jour pendant une période définie.
on: failure
ou on: success
: Utilisé pour exécuter les étapes de nettoyage ou des actions de restauration.
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 preDeploy
deploy
, routeTraffic
et 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 d’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 les instances de la nouvelle version de l’application sur un ensemble fixe de machines virtuelles (ensemble propagé) à chaque itération.
Actuellement, nous prenons uniquement en charge la stratégie de déploiement propagé vers des ressources de machine virtuelle.
Par exemple, un déploiement propagé attend généralement que les déploiements sur chaque ensemble de machines virtuelles se terminent avant de passer à l’ensemble suivant de déploiements. Vous pouvez effectuer un contrôle d’intégrité après chaque itération et si un problème important se produit, le déploiement propagé peut être arrêté.
Les déploiements propagés 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, un déploiement propagé.
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 les travaux de hook de cycle de vie sont créés 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 cibles de machine virtuelle sur lesquelles effectuer un déploiement en parallèle. Cela garantit que l’application s’exécute sur ces machines et qu’elle est capable de gérer les demandes pendant que le déploiement a lieu sur le reste des machines, ce qui réduit le temp d’arrêt global.
Notes
Il existe quelques lacunes connues dans cette fonctionnalité. Par exemple, lorsque vous retentez un index, elle va réexécuter le déploiement sur toutes les machines virtuelles, pas seulement sur les cibles ayant échoué.
Stratégie de déploiement avec contrôle de validité
La stratégie de déploiement avec contrôle de validité est une stratégie de déploiement avancée qui permet d’atténuer les risques liés au 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 avec contrôle de validité prend en charge le hook de cycle de vie preDeploy
(exécuté une seule 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. Exemple : « canari ».
strategy.action
: Action à effectuer sur le cluster Kubernetes. Par exemple, déployer, promouvoir ou rejeter.
strategy.increment
: Valeur d’incrément utilisée dans l’interaction actuelle. Cette variable est disponible uniquement dans les hooks de cycle de vie deploy
, routeTraffic
et postRouteTraffic
.
Exemples
Stratégie de déploiement RunOnce
L’exemple d’extrait de code YAML suivant présente 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 validation.
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
Avec chaque exécution de ce travail, l’historique de déploiement est enregistré sur l’environnement smarthotel-dev
.
Notes
- Il est également possible de créer un environnement avec des ressources vides et de l’utiliser comme interpréteur de commandes abstrait pour enregistrer l’historique de déploiement, comme illustré dans l’exemple précédent.
L’exemple suivant montre comment un pipeline peut faire référence à un environnement et à une ressource à utiliser comme cible pour un travail 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@0
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 de déploiement sur une ressource spécifique au sein de l’environnement, au lieu d’enregistrer l’historique sur toutes les ressources au sein de l’environnement.
- Les étapes du travail 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 le travail de déploiement est lié à l’environnement. Cela s’avère utile dans les cas où le même détail de connexion est défini pour plusieurs étapes du travail.
Remarque
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é au sein d’un réseau virtuel qui a accès au réseau virtuel du cluster. Pour plus d’informations, consultez les options de connexion au cluster privé.
Stratégie de déploiement propagé
La stratégie de déploiement propagé pour les machines virtuelles met à jour jusqu’à cinq cibles dans chaque itération. maxParallel
détermine le nombre de cibles qui peuvent simultanément faire l’objet d’un déploiement. 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 lors d’un 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 avec contrôle de validité pour AKS va d’abord déployer les changements sur 10 % des pods, puis 20 %, tout en supervisant l’intégrité pendant postRouteTraffic
. Si tout se passe bien, une promotion jusqu’à 100 pour cent aura lieu.
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@0
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...
Utiliser des éléments décorateurs de pipeline pour injecter automatiquement des étapes
Des éléments décoratifs de pipeline peuvent être utilisés dans les travaux de déploiement pour injecter automatiquement n’importe quelle étape personnalisée (par exemple, l’analyseur de vulnérabilité) dans l’exécution de chaque hook de cycle de vie de chaque travail de déploiement. Étant donné que les éléments décoratifs de pipeline peuvent être appliqués à tous les pipelines dans une organisation, ils sont applicables dans le cadre de pratiques de déploiement sécurisées.
En outre, les travaux de déploiement peuvent être exécutés en tant que travail de conteneur avec un side-car de services s’il est défini.
Prise en charge des variables de sortie
Définissez des variables de sortie dans les hooks de cycle de vie d’un travail de déploiement et consommez-les dans d’autres étapes et travaux en aval au sein du même index.
Pour partager des variables entre des index, générez un artefact dans un index, puis consommez-le dans un index ultérieur, ou bien utilisez la syntaxe stageDependencies
décrite dans les variables.
Lors de l’exécution de stratégies de déploiement, vous pouvez accéder aux variables de sortie entre les travaux à l’aide de la syntaxe suivante.
- Pour une stratégie runOnce :
$[dependencies.<job-name>.outputs['<job-name>.<step-name>.<variable-name>']]
(par exemple,$[dependencies.JobA.outputs['JobA.StepA.VariableA']]
) - Pour une stratégie runOnce plus un resourceType :
$[dependencies.<job-name>.outputs['Deploy_<resource-name>.<step-name>.<variable-name>']]
. (Par exemple,$[dependencies.JobA.outputs['Deploy_VM1.StepA.VariableA']]
) - Pour une stratégie avec contrôle de validité :
$[dependencies.<job-name>.outputs['<lifecycle-hookname>_<increment-value>.<step-name>.<variable-name>']]
- Pour une stratégie de propagation :
$[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 un travail runOnce
, spécifiez le nom du travail 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 un travail de déploiement, la syntaxe de la variable de sortie varie en fonction de la façon dont l’environnement est défini. Dans cet exemple, env1
utilise une notation abrégée et env2
inclut la syntaxe complète dans 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 extrayez une variable d’un travail à l’étape 1, le fait de le référencer à partir d’un travail de déploiement à 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 extrayez une variable à partir d’un travail de déploiement, utilisez la syntaxe stageDependencies pour la référencer à partir de la phase 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)
Découvrez-en plus sur la définition d’une variable de sortie multi-travaux.
Questions fréquentes (FAQ)
Mon pipeline est bloqué avec le message « Travail en attente... ». Comment puis-je résoudre ce problème ?
Ce problème peut se produire en cas de conflit de noms entre deux travaux. Vérifiez que tous les travaux de déploiement inclus dans le même index portent un nom unique et que les noms des travaux et des index ne contiennent pas de mots clés. Si un renommage ne résout pas le problème, passez en revue la section sur la résolution des problèmes d’exécutions de pipeline.
Les éléments décoratifs sont-ils pris en charge dans les groupes de déploiement ?
Non. Vous ne pouvez pas utiliser d’éléments décoratifs dans des groupes de déploiement.