Skip to content

Azure Pipelines is the CI/CD service in Azure DevOps (alongside Boards, Repos, Test Plans and Artifacts). It builds and deploys any language to any platform from GitHub, Azure Repos, Bitbucket or others. Concepts are in CI-CD Pipelines.

Azure DevOps services

Service Purpose
Azure Boards Work items, backlogs, sprints
Azure Repos Git repositories
Azure Pipelines Build, test, deploy
Azure Test Plans Manual and exploratory testing
Azure Artifacts Package feeds (NuGet, npm, Maven, Python)

Concepts

Term Meaning
Pipeline The full definition (azure-pipelines.yml)
Trigger trigger (CI), pr (pull request), schedules
Stage Major phase, e.g. Build, Dev, Prod
Job Runs on one agent; jobs in a stage run in parallel by default
Step A script or a task
Task Packaged action (DotNetCoreCLI@2, AzureWebApp@1, Docker@2)
Agent Machine that runs a job; Microsoft-hosted (ubuntu-latest) or self-hosted
Agent pool Group of agents
Service connection Stored, secured link to Azure, AWS, Docker registry, Kubernetes, GitHub
Variable group Shared variables, can link to Key Vault
Environment Deployment target with approvals and checks
Artifact Build output published with PublishPipelineArtifact

Pipelines can be YAML (preferred, in the repo) or Classic (visual editor, legacy; Classic Release pipelines are being replaced by multi-stage YAML).


Multi-stage YAML Pipeline

# azure-pipelines.yml
trigger:
  branches:
    include: [main]

pr:
  branches:
    include: [main]

pool:
  vmImage: ubuntu-latest

variables:
  - group: shop-api-shared          # variable group
  - name: imageTag
    value: $(Build.BuildId)

stages:
  - stage: Build
    jobs:
      - job: BuildTest
        steps:
          - task: UsePythonVersion@0
            inputs:
              versionSpec: '3.12'
          - script: |
              pip install -r requirements.txt
              pytest --junitxml=results.xml
            displayName: Install and test
          - task: PublishTestResults@2
            condition: succeededOrFailed()
            inputs:
              testResultsFiles: results.xml
          - task: Docker@2
            inputs:
              command: buildAndPush
              containerRegistry: acr-connection     # service connection
              repository: shop-api
              tags: $(imageTag)

  - stage: Staging
    dependsOn: Build
    jobs:
      - deployment: DeployStaging
        environment: staging
        strategy:
          runOnce:
            deploy:
              steps:
                - task: AzureWebAppContainer@1
                  inputs:
                    azureSubscription: azure-connection
                    appName: shop-api-staging
                    containers: myregistry.azurecr.io/shop-api:$(imageTag)

  - stage: Production
    dependsOn: Staging
    condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
    jobs:
      - deployment: DeployProd
        environment: production          # approvals configured on this environment
        strategy:
          runOnce:
            deploy:
              steps:
                - task: AzureWebAppContainer@1
                  inputs:
                    azureSubscription: azure-connection
                    appName: shop-api-prod
                    containers: myregistry.azurecr.io/shop-api:$(imageTag)

Deployment targets: 2. Azure Compute (App Service, ACR, AKS, Functions).


Variables and Expressions

Syntax When resolved Example
$(var) Runtime macro $(Build.BuildId)
${{ variables.x }} Compile time template expression conditional insertion
$[ variables.x ] Runtime expression in condition / variable definitions

Common predefined variables: Build.BuildId, Build.SourceBranch, Build.SourceVersion, Pipeline.Workspace, System.DefaultWorkingDirectory.

Secrets: mark variables secret, or link a variable group to Key Vault (5. Azure Identity and Security). Secret variables are not passed to scripts automatically; map them through env:.

- script: ./deploy.sh
  env:
    API_KEY: $(apiKey)

Deployment Jobs and Strategies

deployment jobs target an environment and record history there.

Strategy Behaviour
runOnce Single execution
rolling Update a few targets at a time (VM environments)
canary Increment traffic to the new version, e.g. 10, 20 percent

Lifecycle hooks: preDeploy, deploy, routeTraffic, postRouteTraffic, on: failure / success.

Approvals and checks

Configure on the environment: manual approval, branch control, business hours, Azure Monitor alerts, required template. This gives gated production releases.


Templates (Reuse)

# templates/build.yml
parameters:
  - name: pythonVersion
    type: string
    default: '3.12'
steps:
  - task: UsePythonVersion@0
    inputs:
      versionSpec: ${{ parameters.pythonVersion }}
  - script: pytest
# azure-pipelines.yml
steps:
  - template: templates/build.yml
    parameters:
      pythonVersion: '3.11'

Templates can be step, job, stage or variable templates, and can live in another repo (resources.repositories).


Matrix and Caching

strategy:
  matrix:
    py311: { python.version: '3.11' }
    py312: { python.version: '3.12' }
steps:
  - task: Cache@2
    inputs:
      key: 'pip | "$(Agent.OS)" | requirements.txt'
      path: $(Pipeline.Workspace)/.pip

Service Connections and Security

  • Azure Resource Manager connection: prefer workload identity federation (OIDC) over client secrets
  • Scope connections to a resource group where possible
  • Restrict who can use connections and which pipelines may access them
  • Use secure files for certificates / keystores
  • Protect main with branch policies (required builds, reviewers)
  • Use Microsoft-hosted agents for clean builds; self-hosted when you need private network access or special tools (vmImage replaced by name: pool)

Azure Pipelines vs GitHub Actions

Azure Pipelines GitHub Actions
Config azure-pipelines.yml, stages/jobs/tasks .github/workflows/*.yml, jobs/actions
Approvals Environment checks Environment protection rules
Reuse Templates Reusable workflows, composite actions
Ecosystem Azure DevOps suite, tight Azure integration Largest marketplace, tied to GitHub
Concepts map Service connection ↔ OIDC / secrets, Variable group ↔ vars/secrets

See GitHub Actions and Jenkins.