Azure DevOps Pipelines
Expert guidance for Azure DevOps CI/CD pipeline configuration.
When to Use This Skill
- Creating YAML-based build pipelines
- Setting up multi-stage deployments
- Configuring pipeline triggers and schedules
- Creating reusable pipeline templates
- Managing artifacts and releases
- Integrating with Azure services
- Setting up deployment environments
Basic Pipeline Structure
# azure-pipelines.yml
trigger:
branches:
include:
- main
- develop
paths:
exclude:
- docs/*
- README.md
pr:
branches:
include:
- main
pool:
vmImage: 'ubuntu-latest'
variables:
- name: buildConfiguration
value: 'Release'
- group: my-variable-group
stages:
- stage: Build
displayName: 'Build Stage'
jobs:
- job: BuildJob
steps:
- task: DotNetCoreCLI@2
inputs:
command: 'build'
projects: '**/*.csproj'
arguments: '--configuration $(buildConfiguration)'
- stage: Test
displayName: 'Test Stage'
dependsOn: Build
jobs:
- job: TestJob
steps:
- task: DotNetCoreCLI@2
inputs:
command: 'test'
projects: '**/*Tests.csproj'
- stage: Deploy
displayName: 'Deploy Stage'
dependsOn: Test
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
jobs:
- deployment: DeployJob
environment: 'production'
strategy:
runOnce:
deploy:
steps:
- script: echo 'Deploying...'
Triggers
# Branch triggers
trigger:
branches:
include:
- main
- release/*
exclude:
- feature/*
# Path filters
trigger:
paths:
include:
- src/*
exclude:
- src/tests/*
# Tag triggers
trigger:
tags:
include:
- v*
# Scheduled triggers
schedules:
- cron: '0 0 * * *'
displayName: 'Nightly build'
branches:
include:
- main
always: true
# PR triggers
pr:
branches:
include:
- main
paths:
include:
- src/*
drafts: false
Variables
# Inline variables
variables:
buildConfiguration: 'Release'
dotnet
# Variable groups (from Library)
variables:
- group: my-secrets
- group: my-config
# Template variables
variables:
- template: variables/common.yml
- name: environment
value: 'production'
# Conditional variables
variables:
${{ if eq(variables['Build.SourceBranch'], 'refs/heads/main') }}:
environment: 'production'
${{ else }}:
environment: 'staging'
# Runtime expressions
variables:
- name: fullPath
value: $(Build.SourcesDirectory)/$(projectName)
Jobs and Steps
jobs:
- job: Build
displayName: 'Build Application'
timeoutInMinutes: 60
pool:
vmImage: 'ubuntu-latest'
steps:
# Checkout
- checkout: self
clean: true
fetchDepth: 0
# Script tasks
- script: |
echo "Building..."
npm install
npm run build
displayName: 'Build with npm'
# PowerShell
- powershell: |
Write-Host "Running PowerShell"
displayName: 'PowerShell script'
# Bash
- bash: |
echo "Running Bash"
displayName: 'Bash script'
# Task shorthand
- task: UseDotNet@2
inputs:
# Download artifact
- download: current
artifact: drop
# Publish artifact
- publish: $(Build.ArtifactStagingDirectory)
artifact: drop
Multi-Stage Pipeline
stages:
- stage: Build
jobs:
- job: BuildJob
steps:
- task: DotNetCoreCLI@2
inputs:
command: 'publish'
publishWebProjects: true
arguments: '--configuration Release --output $(Build.ArtifactStagingDirectory)'
- publish: $(Build.ArtifactStagingDirectory)
artifact: webapp
- stage: DeployDev
displayName: 'Deploy to Dev'
dependsOn: Build
jobs:
- deployment: DeployDev
environment: 'dev'
strategy:
runOnce:
deploy:
steps:
- download: current
artifact: webapp
- task: AzureWebApp@1
inputs:
azureSubscription: 'Azure-Connection'
appName: 'myapp-dev'
package: '$(Pipeline.Workspace)/webapp/**/*.zip'
- stage: DeployProd
displayName: 'Deploy to Production'
dependsOn: DeployDev
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
jobs:
- deployment: DeployProd
environment: 'production'
strategy:
runOnce:
deploy:
steps:
- download: current
artifact: webapp
- task: AzureWebApp@1
inputs:
azureSubscription: 'Azure-Connection'
appName: 'myapp-prod'
package: '$(Pipeline.Workspace)/webapp/**/*.zip'
Templates
Step Template
# templates/build-steps.yml
parameters:
- name: buildConfiguration
type: string
default: 'Release'
- name: projects
type: string
steps:
- task: DotNetCoreCLI@2
displayName: 'Restore packages'
inputs:
command: 'restore'
projects: ${{ parameters.projects }}
- task: DotNetCoreCLI@2
displayName: 'Build'
inputs:
command: 'build'
projects: ${{ parameters.projects }}
arguments: '--configuration ${{ parameters.buildConfiguration }}'
Job Template
# templates/build-job.yml
parameters:
- name: name
type: string
- name: pool
type: object
default:
vmImage: 'ubuntu-latest'
jobs:
- job: ${{ parameters.name }}
pool: ${{ parameters.pool }}
steps:
- template: build-steps.yml
parameters:
buildConfiguration: 'Release'
projects: '**/*.csproj'
Stage Template
# templates/deploy-stage.yml
parameters:
- name: environment
type: string
- name: azureSubscription
type: string
- name: appName
type: string
stages:
- stage: Deploy_${{ parameters.environment }}
displayName: 'Deploy to ${{ parameters.environment }}'
jobs:
- deployment: Deploy
environment: ${{ parameters.environment }}
strategy:
runOnce:
deploy:
steps:
- task: AzureWebApp@1
inputs:
azureSubscription: ${{ parameters.azureSubscription }}
appName: ${{ parameters.appName }}
package: '$(Pipeline.Workspace)/**/*.zip'
Using Templates
# azure-pipelines.yml
trigger:
- main
stages:
- stage: Build
jobs:
- template: templates/build-job.yml
parameters:
name: BuildApp
- template: templates/deploy-stage.yml
parameters:
environment: 'dev'
azureSubscription: 'Azure-Dev'
appName: 'myapp-dev'
- template: templates/deploy-stage.yml
parameters:
environment: 'prod'
azureSubscription: 'Azure-Prod'
appName: 'myapp-prod'
Common Tasks
Docker
- task: Docker@2
inputs:
containerRegistry: 'myacr'
repository: 'myapp'
command: 'buildAndPush'
Dockerfile: '**/Dockerfile'
tags: |
$(Build.BuildId)
latest
Kubernetes
- task: KubernetesManifest@0
inputs:
action: 'deploy'
kubernetesServiceConnection: 'aks-connection'
namespace: 'default'
manifests: |
manifests/deployment.yml
manifests/service.yml
containers: |
myacr.azurecr.io/myapp:$(Build.BuildId)
Terraform
- task: TerraformInstaller@0
inputs:
terraform
- task: TerraformTaskV4@4
inputs:
provider: 'azurerm'
command: 'init'
workingDirectory: '$(System.DefaultWorkingDirectory)/terraform'
backendServiceArm: 'Azure-Connection'
backendAzureRmResourceGroupName: 'tfstate-rg'
backendAzureRmStorageAccountName: 'tfstatestorage'
backendAzureRmContainerName: 'tfstate'
backendAzureRmKey: 'terraform.tfstate'
- task: TerraformTaskV4@4
inputs:
provider: 'azurerm'
command: 'apply'
workingDirectory: '$(System.DefaultWorkingDirectory)/terraform'
environmentServiceNameAzureRM: 'Azure-Connection'
Testing
- task: DotNetCoreCLI@2
inputs:
command: 'test'
projects: '**/*Tests.csproj'
arguments: '--configuration $(buildConfiguration) --collect:"XPlat Code Coverage"'
- task: PublishCodeCoverageResults@1
inputs:
codeCoverageTool: 'Cobertura'
summaryFileLocation: '$(Agent.TempDirectory)/**/coverage.cobertura.xml'
Environments and Approvals
# Environment with approvals (configure in Azure DevOps UI)
jobs:
- deployment: DeployProd
environment: 'production' # Requires approval
strategy:
runOnce:
deploy:
steps:
- script: echo 'Deploying to production'
# Deployment strategies
strategy:
canary:
increments: [10, 20, 50, 100]
deploy:
steps:
- script: echo 'Canary deployment'
strategy:
rolling:
maxParallel: 2
deploy:
steps:
- script: echo 'Rolling deployment'
Best Practices
- Use Templates for reusable pipeline components
- Separate Stages for build, test, and deploy
- Use Variable Groups for secrets and shared config
- Enable Branch Policies for PR validation
- Use Environments with approval gates
- Cache Dependencies to speed up builds
- Use Service Connections for Azure resources
- Pin Task Versions to avoid breaking changes
微信扫一扫