Azure DevOps Pipelines provides a comprehensive CI/CD platform integrated with Azure. In this guide, we’ll build a complete pipeline that includes building, testing, and deploying a containerized application to AKS.
Pipeline Structure
A well-structured Azure DevOps pipeline follows this pattern:
Trigger → Build → Test → Publish → Deploy (Dev) → Deploy (Staging) → Deploy (Prod)
Multi-Stage YAML Pipeline
# azure-pipelines.yml
trigger:
branches:
include:
- main
- release/*
paths:
exclude:
- README.md
- docs/**
variables:
containerRegistry: 'myacr.azurecr.io'
imageRepository: 'myapp'
dockerfilePath: '$(Build.SourcesDirectory)/Dockerfile'
tag: '$(Build.BuildId)'
stages:
- stage: Build
displayName: 'Build & Test'
jobs:
- job: BuildAndTest
pool:
vmImage: 'ubuntu-latest'
steps:
- task: UseDotNet@2
inputs:
packageType: 'sdk'
version: '8.x'
- script: dotnet restore
displayName: 'Restore dependencies'
- script: dotnet build --no-restore --configuration Release
displayName: 'Build'
- script: dotnet test --no-build --configuration Release --logger trx
displayName: 'Run Tests'
- task: PublishTestResults@2
inputs:
testResultsFormat: 'VSTest'
testResultsFiles: '**/*.trx'
- task: Docker@2
displayName: 'Build & Push Docker image'
inputs:
command: buildAndPush
repository: $(imageRepository)
dockerfile: $(dockerfilePath)
containerRegistry: 'myACRConnection'
tags: |
$(tag)
latest
Deployment to AKS
- stage: DeployDev
displayName: 'Deploy to Development'
dependsOn: Build
condition: succeeded()
variables:
- group: dev-variables
jobs:
- deployment: DeployToDev
displayName: 'Deploy to AKS Dev'
environment: 'development.default'
strategy:
runOnce:
deploy:
steps:
- task: KubernetesManifest@1
displayName: 'Deploy to Kubernetes'
inputs:
action: 'deploy'
connectionType: 'azureResourceManager'
azureSubscriptionConnection: 'My Azure Subscription'
azureResourceGroup: 'myapp-dev-rg'
kubernetesCluster: 'myapp-dev-aks'
manifests: |
$(Pipeline.Workspace)/manifests/deployment.yaml
$(Pipeline.Workspace)/manifests/service.yaml
containers: '$(containerRegistry)/$(imageRepository):$(tag)'
Environment Approval Gates
For production deployments, use approval gates:
- stage: DeployProd
displayName: 'Deploy to Production'
dependsOn: DeployStaging
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
jobs:
- deployment: DeployToProd
displayName: 'Deploy to AKS Production'
environment: 'production.default' # Has manual approval configured
strategy:
runOnce:
deploy:
steps:
- task: KubernetesManifest@1
inputs:
action: 'deploy'
manifests: '$(Pipeline.Workspace)/k8s/production/**'
containers: '$(containerRegistry)/$(imageRepository):$(tag)'
Pipeline Templates
Create reusable templates to avoid code duplication:
# templates/deploy-to-aks.yml
parameters:
- name: environment
type: string
- name: imageTag
type: string
- name: kubernetesServiceConnection
type: string
steps:
- task: KubernetesManifest@1
displayName: 'Deploy ${{ parameters.environment }}'
inputs:
action: 'deploy'
kubernetesServiceConnection: '${{ parameters.kubernetesServiceConnection }}'
namespace: '${{ parameters.environment }}'
manifests: '$(Pipeline.Workspace)/manifests/**'
containers: '$(containerRegistry)/$(imageRepository):${{ parameters.imageTag }}'
Security Best Practices
- Use variable groups for sensitive configuration
- Enable secret scanning with Azure Defender
- Implement branch policies to require PR reviews
- Use service principals with minimum required permissions
- Rotate secrets regularly using Azure Key Vault integration
Conclusion
Azure DevOps Pipelines provides everything you need for enterprise-grade CI/CD. By using multi-stage pipelines, approval gates, and reusable templates, you can build reliable, automated deployment processes that scale with your organization.