Azure DevOps YAML Pipeline CI/CD Setup
Goal
Build a single YAML pipeline that builds a Docker container, pushes it to Azure Container Registry, and deploys it sequentially to dev and int environments with approval gates.
Key Points
- Use a single pipeline for CI-CD (no way to pass BuildId between separate pipelines)
- Environments are auto-created on first deployment
- Configure approvals directly on environments in Azure DevOps
- Create Service Connection before running pipeline
Pipeline Structure
Trigger on master branch push:
trigger:
- master
resources:
- repo: self
Variables - use BuildId as container tag:
variables:
dockerRegistryServiceConnection: 'ra076bb1-83c4-4bff-9c7d-d2e1b7918498'
imageRepository: 'bustroker.yamlpipelines.webapi'
containerRegistry: 'bustrokeryamlpipelines.azurecr.io'
dockerfilePath: '$(Build.SourcesDirectory)/Bustroker.YamlPipelines.WebApi/Dockerfile'
tag: '$(Build.BuildId)'
vmImageName: 'ubuntu-latest'
Stage 1: Build and Push
stages:
- stage: BuildStage
displayName: Build
jobs:
- job: Build
displayName: Build and push
pool:
vmImage: $(vmImageName)
steps:
- task: Docker@2
displayName: Build and push an image to container registry
inputs:
command: buildAndPush
repository: $(imageRepository)
dockerfile: $(dockerfilePath)
containerRegistry: $(dockerRegistryServiceConnection)
tags: |
$(tag)
Stage 2: Deploy to Dev
- stage: DevDeployStage
dependsOn: BuildStage
displayName: Dev
jobs:
- deployment: DevDeploymentJob
displayName: Deploy to dev
environment: dev
strategy:
runOnce:
deploy:
steps:
- task: AzureWebAppContainer@1
inputs:
azureSubscription: 'AzDevOps.ServiceConnection'
appName: 'bustroker-yamlpipelines-webapi-dev'
containers: '$(containerRegistry)/$(imageRepository):$(tag)'
appSettings: '-ASPNETCORE_ENVIRONMENT dev'
Stage 3: Deploy to Int
- stage: IntDeployStage
dependsOn: DevDeployStage
displayName: Int
jobs:
- deployment: IntDeploymentJob
displayName: Deploy to int
environment: int
pool:
vmImage: $(vmImageName)
strategy:
runOnce:
deploy:
steps:
- task: AzureWebAppContainer@1
inputs:
azureSubscription: 'AzDevOps.ServiceConnection'
appName: 'bustroker-yamlpipelines-webapi-int'
containers: '$(containerRegistry)/$(imageRepository):$(tag)'
appSettings: '-ASPNETCORE_ENVIRONMENT int'
Complete Pipeline
## Docker
## Build and push an image to Azure Container Registry
## https://docs.microsoft.com/azure/devops/pipelines/languages/docker
trigger:
- master
resources:
- repo: self
variables:
# Container registry service connection established during pipeline creation
dockerRegistryServiceConnection: 'ra076bb1-83c4-4bff-9c7d-d2e1b7918498'
imageRepository: 'bustroker.yamlpipelines.webapi'
containerRegistry: 'bustrokeryamlpipelines.azurecr.io'
dockerfilePath: '$(Build.SourcesDirectory)/Bustroker.YamlPipelines.WebApi/Dockerfile'
tag: '$(Build.BuildId)'
# Agent VM image name
vmImageName: 'ubuntu-latest'
stages:
- stage: BuildStage
displayName: Build
jobs:
- job: Build
displayName: Build and push
pool:
vmImage: $(vmImageName)
steps:
- task: Docker@2
displayName: Build and push an image to container registry
inputs:
command: buildAndPush
repository: $(imageRepository)
dockerfile: $(dockerfilePath)
containerRegistry: $(dockerRegistryServiceConnection)
tags: |
$(tag)
- stage: DevDeployStage
dependsOn: BuildStage
displayName: Dev
jobs:
- deployment: DevDeploymentJob
displayName: Deploy to dev
environment: dev
strategy:
runOnce:
deploy:
steps:
- task: AzureWebAppContainer@1
inputs:
azureSubscription: 'AzDevOps.ServiceConnection'
appName: 'bustroker-yamlpipelines-webapi-dev'
containers: '$(containerRegistry)/$(imageRepository):$(tag)'
appSettings: '-ASPNETCORE_ENVIRONMENT dev'
- stage: IntDeployStage
dependsOn: DevDeployStage
displayName: Int
jobs:
- deployment: IntDeploymentJob
displayName: Deploy to int
environment: int
pool:
vmImage: $(vmImageName)
strategy:
runOnce:
deploy:
steps:
- task: AzureWebAppContainer@1
inputs:
azureSubscription: 'AzDevOps.ServiceConnection'
appName: 'bustroker-yamlpipelines-webapi-int'
containers: '$(containerRegistry)/$(imageRepository):$(tag)'
appSettings: '-ASPNETCORE_ENVIRONMENT int'