HT
How Things Work
System Online

Azure DevOps Pipelines

How YAML pipelines move code from commit to production through agents, artifacts, environments, approvals, and deployment gates.

How It Works

Azure DevOps Pipelines is a CI/CD orchestration system. A pipeline run starts from a commit or manual trigger, executes jobs on agents, publishes immutable artifacts, and promotes those artifacts through environments. The important internal idea is separation of concerns: build creates the package, release promotes the same package, and environments apply checks before production changes happen.

1
Trigger creates a run

A commit, pull request, scheduled trigger, or manual queue creates an immutable pipeline run. The run captures the YAML version, source commit SHA, variables, and permissions at that moment. That snapshot matters: changing YAML after a run starts does not change the active run.

2
Agent executes jobs in isolated workspaces

Each job runs on an agent: Microsoft-hosted, self-hosted, or containerized. The agent checks out source, restores tools, runs steps, and streams logs back to Azure DevOps. Jobs do not share filesystem state unless you explicitly publish artifacts, cache dependencies, or use pipeline variables.

3
Build once, publish an artifact

The build stage compiles and tests the application, then publishes a versioned artifact. Later stages should deploy that exact artifact instead of rebuilding from source. Rebuilding per environment creates drift: staging and production may not actually run the same bits.

4
Deployment jobs target environments

Deployment jobs bind a release to an environment such as staging or production. Environments can enforce approvals, business-hour checks, branch controls, and resource history. They also give an audit trail of what version went where and who approved it.

5
Gates decide whether promotion continues

Quality gates stop bad changes before production: unit tests, vulnerability scans, infrastructure validation, smoke tests, approval checks, and health probes. A good pipeline fails early for code issues and blocks late for human or operational risk.

Key Concepts

STStage

A major phase of the pipeline such as Build, Staging, or Production. Stages define dependency order and are the natural place for approvals and promotion boundaries.

JBJob

A set of steps that runs on one agent. Jobs can run in parallel, but each job gets its own workspace unless artifacts or caches are used.

PKArtifact

The packaged output of a build. Production should deploy the same artifact that passed tests in earlier stages, not a fresh rebuild.

ENEnvironment

A deployment target with history, approvals, checks, and resource metadata. Use environments for staging and production instead of plain script steps.

IDService Connection

The identity and credentials Azure DevOps uses to deploy into Azure. Prefer workload identity federation or managed service principals over long-lived secrets.

SLDeployment Slot

An App Service staging slot lets you deploy, warm, test, and then swap to production with minimal downtime.

YAML pipeline with artifact promotion, staging slot deploy, and production swap
tsx
1# azure-pipelines.yml - build once, promote the same artifact
2trigger:
3 branches:
4 include:
5 - main
6
7variables:
8 buildConfiguration: Release
9 artifactName: webapp
10
11stages:
12- stage: Build
13 jobs:
14 - job: BuildAndTest
15 pool:
16 vmImage: ubuntu-latest
17 steps:
18 - task: UseDotNet@2
19 inputs:
20 packageType: sdk
21 version: 8.x
22 - script: dotnet restore
23 - script: dotnet build --configuration $(buildConfiguration) --no-restore
24 - script: dotnet test --configuration $(buildConfiguration) --no-build
25 - task: DotNetCoreCLI@2
26 inputs:
27 command: publish
28 publishWebProjects: true
29 arguments: --configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)
30 zipAfterPublish: true
31 - publish: $(Build.ArtifactStagingDirectory)
32 artifact: $(artifactName)
33
34- stage: Staging
35 dependsOn: Build
36 jobs:
37 - deployment: DeployStaging
38 environment: app-staging
39 strategy:
40 runOnce:
41 deploy:
42 steps:
43 - download: current
44 artifact: $(artifactName)
45 - task: AzureWebApp@1
46 inputs:
47 azureSubscription: sc-prod
48 appName: app-orders-prod
49 deployToSlotOrASE: true
50 slotName: staging
51 package: $(Pipeline.Workspace)/$(artifactName)/**/*.zip
52
53- stage: Production
54 dependsOn: Staging
55 jobs:
56 - deployment: SwapProduction
57 environment: app-production # approval checks live here
58 strategy:
59 runOnce:
60 deploy:
61 steps:
62 - task: AzureAppServiceManage@0
63 inputs:
64 azureSubscription: sc-prod
65 WebAppName: app-orders-prod
66 SourceSlot: staging
67 SwapWithProduction: true
💡
Why This Matters

Pipelines are production control planes. A small YAML mistake can bypass approvals, deploy different code than the version tested in staging, leak secrets through logs, or swap the wrong App Service settings. Understanding agents, artifacts, environments, service connections, and deployment jobs turns CI/CD from a pile of scripts into a reliable release system.

Common Pitfalls

Rebuilding per environment means staging and production may run different binaries. Build once and promote the artifact.
Using a normal job for production deployment bypasses environment approval checks. Use deployment jobs that target the production environment.
Service connections with broad subscription permissions are dangerous. Scope them to the resource group or workload, and prefer federated credentials over stored secrets.
Secret variables are masked in logs, but derived values and transformed secrets may not be. Avoid echoing environment dumps in pipelines.
App Service slot swaps can move non-sticky settings. Mark environment-specific settings as slot-sticky before automating swaps.
Real-World Use Cases

1Production Ran Different Code Than Staging

Scenario

A team had separate staging and production stages, but each stage rebuilt the app from source before deploying. Staging passed smoke tests. Production failed with a dependency mismatch 20 minutes later.

Problem

The production stage restored a newer transitive package version because the dependency lock was not enforced. Staging and production looked like the same commit, but they were not the same artifact.

Solution

Changed the pipeline to build once, publish a zipped artifact, and deploy that artifact to every environment. Added lock-file restore and artifact checksum logging.

💡

Takeaway: A release pipeline should promote an artifact, not a Git branch. Build once, verify once, promote the same bits.

2Approval Gate Bypassed by a Script Task

Scenario

Production deployments required approval in Azure DevOps, but one YAML path used a regular job with an Azure CLI task instead of a deployment job.

Problem

Environment approvals only apply to deployment jobs targeting that environment. The script had production credentials through a service connection, so it deployed without triggering the approval gate.

Solution

Moved all production changes into deployment jobs targeting the production environment. Scoped the production service connection to only those jobs and enabled branch controls.

💡

Takeaway: Approvals protect environments, not arbitrary scripts. Use deployment jobs for anything that changes production.

3Slot Swap Sent Staging Settings to Production

Scenario

A pipeline deployed to an App Service staging slot and swapped to production. After the swap, the app started calling staging dependencies from production traffic.

Problem

Several app settings were not marked slot-sticky. During the swap, environment-specific settings moved with the app code.

Solution

Marked database connections, API endpoints, and feature flags as deployment slot settings. Added a pre-swap validation step that compares slot-sticky settings against an allowlist.

💡

Takeaway: Deployment automation must know platform behavior. Slot swaps are safe only when slot-specific settings stay pinned to the slot.

Join the discussion

Comments

?

Loading comments...

Cookie preferences

We use essential cookies for sign-in and preferences. With your permission, we also use basic analytics to improve lessons.