Implementing Azure Pipelines

Azure Pipelines is Microsoft’s CI/CD: YAML (or classic UI) that builds, tests, and deploys. Treat the YAML as code in the same repo as the app. Classic UI-only pipelines drift and cannot be reviewed.

A boring pipeline

  1. Trigger on main and PRs.
  2. Restore, build, test (unit + a fast integration slice).
  3. Publish an artifact (zip, container image, NuGet) — one build.
  4. Deploy jobs to staging then prod with environments and approvals if you need them.
trigger:
  - main
pool:
  vmImage: ubuntu-latest
steps:
  - task: UseDotNet@2
    inputs:
      packageType: sdk
      version: 8.x
  - script: dotnet test --configuration Release
  - task: Docker@2
    inputs:
      command: buildAndPush
      repository: contoso/api
      tags: $(Build.SourceVersion)

Pin the major you run in production. The 8.x pin is valid through 2026-11-10. The current LTS after that is .NET 10. This sample is not a claim that every app has moved.

Prefer Microsoft-hosted agents until you must see a private network; then a self-hosted agent with a locked-down identity.

Environments and secrets

Pipeline variables marked secret, or variable groups / Key Vault. Do not echo secrets. Environment approvals and checks (business hours, required reviewers) belong on prod, not on every PR build.

What breaks it

The deploy stage checks out source again, compiles again, and tags latest. Download the artifact from the build stage and deploy the image whose tag is the git SHA.

steps:
  - script: dotnet publish -c Release
  - script: docker build -t contoso/api:latest .
steps:
  - download: current
    artifact: drop

Pitfalls

  • Building a different commit than you deploy.
  • latest tags with no digest in prod.
  • A 2,000-line YAML with no templates and a single person who understands it.

App hosting: .NET app deployment. K8s: Kubernetes.