LearnwithVishnu
Basics → Production → Architect
← Home
🔷Azure DevOps
BeginnerEngineerArchitectRepos, Pipelines, Environments, Approvals, Variable Groups, Templates — complete guide
What is Azure DevOpsYAML PipelineEnvironmentsVariables & SecretsTemplatesInterview Q&A

🔷 What is Azure DevOps?

What is Azure DevOps?

Azure DevOps is Microsoft's complete DevOps platform — a suite of integrated services covering the entire software development lifecycle from planning to deployment. It is a cloud-based service (dev.azure.com) that you can also self-host as Azure DevOps Server (formerly TFS).

You can use all services together as a complete platform, or independently — for example, use only Azure Pipelines for CI/CD while keeping your code in GitHub and work items in Jira.

The five services inside Azure DevOps

ServiceWhat it doesAlternative
Azure ReposManaged Git repositories with branch policies, PR reviews, and code review workflowsGitHub, GitLab
Azure PipelinesCI/CD platform — build, test, and deploy using YAML or classic UI. Supports any language, any platform, any cloud.Jenkins, GitHub Actions
Azure BoardsAgile project management — work items, sprints, Kanban boards, backlogs, velocity chartsJira, Trello
Azure ArtifactsPackage management — host npm, Maven, NuGet, Python, and Docker packages with versioningNexus, Artifactory
Azure Test PlansManual and automated test management, exploratory testing, test case trackingTestRail, Zephyr

Why Azure DevOps over alternatives?

Azure DevOps integrates deeply with the Microsoft ecosystem — Azure, Office 365, Active Directory, Teams. If your organisation uses Azure cloud, AKS, and Microsoft 365, Azure DevOps gives you single sign-on via Azure AD, tight AKS integration, Key Vault integration for pipeline secrets, and native connections to Azure resources. This is why it is common in enterprise environments running on Azure — including at PACE Hospitals where you used it for CI/CD automation.

How a pipeline connects to your infrastructure

Developer pushes code to Azure Repos or GitHub
    ↓ trigger: push to main branch
Azure Pipeline starts — runs on Microsoft-hosted or self-hosted agent
    ↓
Build → Test → Docker build → Push image to ACR
    ↓
Deploy to AKS dev (automatic) → Deploy to staging (automatic)
    ↓
Production: manual approval required from release manager
    ↓
Production deployment proceeds → smoke tests → monitoring

📄 YAML Pipeline — Complete Structure

Everything you need to know about Azure DevOps YAML pipelines

trigger:
  branches:
    include: [main, release/*]
  paths:
    exclude: [docs/*, README.md]   # don't trigger on doc changes

pr:
  branches:
    include: [main]

variables:
  - group: production-secrets        # Variable Group from Library
  - name: imageTag
    value: $(Build.BuildNumber)
  - name: containerRegistry
    value: myacr.azurecr.io

stages:
- stage: Build
  displayName: Build and Scan
  jobs:
  - job: BuildJob
    pool:
      vmImage: ubuntu-latest         # Microsoft-hosted agent
    steps:
    - task: Docker@2
      displayName: Build image
      inputs:
        command: build
        repository: myapp
        dockerfile: Dockerfile
        tags: $(imageTag)

    - task: trivy@1
      displayName: Scan for CVEs
      inputs:
        image: myapp:$(imageTag)
        exitCode: 1
        severity: HIGH,CRITICAL

    - task: Docker@2
      displayName: Push to ACR
      inputs:
        command: push
        containerRegistry: acr-service-connection
        repository: myapp
        tags: $(imageTag)

    - publish: $(Build.ArtifactStagingDirectory)
      artifact: manifests

- stage: DeployDev
  displayName: Deploy to Development
  dependsOn: Build
  condition: succeeded()
  jobs:
  - deployment: DeployDev
    pool:
      vmImage: ubuntu-latest
    environment: development         # Environment with approval gates
    strategy:
      runOnce:
        deploy:
          steps:
          - task: HelmDeploy@0
            inputs:
              connectionType: Kubernetes Service Connection
              kubernetesServiceEndpoint: aks-dev-connection
              namespace: dev
              command: upgrade
              chartPath: charts/myapp
              releaseName: myapp
              overrideValues: image.tag=$(imageTag)
              waitForExecution: true

- stage: DeployProd
  displayName: Deploy to Production
  dependsOn: DeployDev
  condition: succeeded()
  jobs:
  - deployment: DeployProd
    environment: production          # Requires approval — configured in Environments UI
    strategy:
      runOnce:
        deploy:
          steps:
          - task: HelmDeploy@0
            inputs:
              namespace: prod
              overrideValues: image.tag=$(imageTag),replicaCount=5

🌍 Environments, Approvals and Gates

Environments are where you control deployment safety

An Environment in Azure DevOps represents a deployment target (development, staging, production). You configure approvals, checks, and gates on the Environment — not in the YAML. This separates deployment logic from deployment safety.

Types of checks on Environments

Check typeWhat it does
Manual approvalSpecific people or groups must approve before the stage proceeds. Used for production deployments.
Invoke REST APICalls an external endpoint — passes if it returns 200. Used for quality gates: SonarQube, ServiceNow ITSM approval.
Business HoursOnly allows deployments during defined hours — prevents weekend production deploys.
Evaluate artifactChecks whether the artifact being deployed meets policies (signed, scanned, from approved branch).
Query Azure Monitor alertsPauses deployment if active alerts exist in the target environment.

Environment resources — track Kubernetes namespaces

# Add a Kubernetes namespace to an Environment for deployment tracking
# Go to: Environments → production → Add resource → Kubernetes → AKS
# After adding: every deployment to that namespace is tracked in Azure DevOps
# You can see: which build deployed, when, who approved, pod health status

🔐 Variables, Variable Groups and Key Vault

Three ways to manage configuration in Azure DevOps pipelines

1. Inline variables (non-sensitive)
variables:
  appName: payment-service
  imageTag: $(Build.BuildNumber)
  environment: production
2. Variable Groups (shared across pipelines)

Pipelines → Library → Variable Groups. Define once, reference in many pipelines. Can mark variables as secret (value hidden in logs). Link a group to a Key Vault to sync secrets automatically.

variables:
  - group: production-config    # all variables from this group are available
  - group: production-secrets   # linked to Azure Key Vault
3. Azure Key Vault integration (recommended for secrets)

Link a Variable Group directly to Azure Key Vault. Every secret in the vault becomes a pipeline variable. Rotates automatically when Key Vault secret changes. No manual copy-paste of secrets.

# Variable Group linked to Key Vault
# In the pipeline, reference Key Vault secrets as normal variables:
- task: AzureCLI@2
  inputs:
    azureSubscription: production-connection
    scriptType: bash
    script: |
      echo "Deploying with DB password: $(database-password)"
      # $(database-password) comes from Key Vault via Variable Group
      # value is masked in logs

Service connections — secure links to external systems

Service connection typeUsed for
Azure Resource ManagerDeploy to Azure, run az CLI commands
KubernetesRun kubectl, helm against AKS cluster
Docker RegistryPush/pull images to ACR or Docker Hub
GitHubCheckout code from GitHub repos

📐 YAML Templates — Reuse Pipeline Code

Templates eliminate duplication across 50 pipeline files

# templates/docker-build.yml — reusable template
parameters:
- name: imageName
  type: string
- name: dockerfilePath
  type: string
  default: Dockerfile
- name: registryConnection
  type: string
  default: acr-connection

steps:
- task: Docker@2
  displayName: Build $(parameters.imageName)
  inputs:
    command: buildAndPush
    repository: $(parameters.imageName)
    dockerfile: $(parameters.dockerfilePath)
    containerRegistry: $(parameters.registryConnection)
    tags: |
      $(Build.BuildNumber)
      latest

---
# Using the template in a pipeline
trigger: [main]
stages:
- stage: Build
  jobs:
  - job: Build
    pool:
      vmImage: ubuntu-latest
    steps:
    - template: templates/docker-build.yml  # reference by path
      parameters:
        imageName: payment-service
        dockerfilePath: services/payment/Dockerfile

    - template: templates/docker-build.yml
      parameters:
        imageName: order-service
        dockerfilePath: services/order/Dockerfile

Stage templates for full environment promotion

# templates/deploy-stage.yml
parameters:
- name: environment
  type: string
- name: namespace
  type: string
- name: imageTag
  type: string

stages:
- stage: Deploy_${{ parameters.environment }}
  jobs:
  - deployment: Deploy
    environment: ${{ parameters.environment }}
    strategy:
      runOnce:
        deploy:
          steps:
          - task: HelmDeploy@0
            inputs:
              namespace: ${{ parameters.namespace }}
              overrideValues: image.tag=${{ parameters.imageTag }}

---
# Main pipeline using the stage template
stages:
- template: templates/deploy-stage.yml
  parameters:
    environment: development
    namespace: dev
    imageTag: $(Build.BuildNumber)
- template: templates/deploy-stage.yml
  parameters:
    environment: production
    namespace: prod
    imageTag: $(Build.BuildNumber)

🎯 Interview Questions

AZURE DEVOPS · ENGINEER
Explain your Azure DevOps CI/CD pipeline from commit to production.
The flow at PACE Hospitals: developer commits to a feature branch. PR created to main branch — branch policy requires 2 reviewers and all pipeline checks to pass before merge. On PR creation: CI pipeline runs automatically — build, unit tests, code quality scan (SonarQube). On merge to main: full CI/CD pipeline triggers. Stage 1 (Build): compile application, run all tests, build Docker image tagged with build number, scan with Trivy for CVEs, push image to ACR, publish Helm chart values as artifact. Stage 2 (Deploy Dev): automatic deployment to dev environment using Helm upgrade, runs smoke tests after deployment. Stage 3 (Deploy Staging): automatic after dev, runs integration tests. Stage 4 (Deploy Production): requires manual approval from release manager AND CAB change request reference. After approval: Helm upgrade to production with rolling update strategy, readiness probes ensure new pods are healthy before old ones terminate, smoke tests validate production. On failure at any stage: Slack notification, automatic rollback via Helm rollback, incident ticket created. Everything is YAML in Git — the pipeline definition is version controlled alongside the application code.
AZURE DEVOPS · ENGINEER
What are Environments in Azure DevOps and how do approvals work?
An Environment in Azure DevOps represents a deployment target — development, staging, production. It is configured separately from the pipeline YAML. The pipeline references the environment by name (environment: production in the deployment job). Approvals are configured on the Environment in the UI — not in YAML. This separation means: the pipeline YAML stays clean and the same, while approval requirements are managed by the operations or change management team. When a pipeline stage references an environment with an approval check: the stage pauses and sends notifications to the configured approvers (individuals or Azure AD groups). Approvers see what is being deployed (build number, commit SHA, PR description) and can approve or reject. Types of checks beyond manual approval: Invoke REST API — call ServiceNow to verify a change ticket is approved. Business Hours — only allow deployments 9am-5pm weekdays. Query Azure Monitor alerts — pause if production has active critical alerts. At PACE: production required approval from the CTO and a CAB change request number as a comment. The pipeline would not proceed until both were provided. Environment also tracks deployment history — you can see every deployment to production, who approved it, which build, what changed.
AZURE DEVOPS · ENGINEER
What is the difference between a self-hosted agent and a Microsoft-hosted agent?
Microsoft-hosted agents: virtual machines provided by Microsoft, spun up fresh for each pipeline run and destroyed after. Advantages: no maintenance, clean environment every run, wide range of images (ubuntu-latest, windows-latest, macOS-latest). Disadvantages: no access to private network resources (your on-premise systems, private AKS clusters), limited cached tools so pip/npm install from scratch every run, cannot run long or resource-intensive builds efficiently. Self-hosted agents: VMs or containers you manage and register with Azure DevOps. Advantages: access to private network (can deploy to private AKS, access on-premise databases), pre-installed tools and caches (faster builds), larger disk and memory for demanding builds, can be inside your VNet. Disadvantages: you maintain them (patching, scaling, monitoring). Agent pools: you create a pool and register agents to it. In the pipeline: pool: name: MyPrivatePool uses your self-hosted pool. For AKS deployments in production: you almost always need self-hosted agents running inside the same VNet as your private AKS cluster — Microsoft-hosted agents cannot reach a private API server. We used self-hosted agents on VMs inside the PACE Azure VNet for all AKS deployments.
AZURE DEVOPS · PRODUCTION
Pipeline is failing at the Docker push step. How do you troubleshoot?
Step 1: read the error message exactly. Common errors: unauthorized: authentication required — service connection credentials are wrong or expired. denied: requested access to the resource is denied — service connection exists but the service principal doesn't have AcrPush role on the registry. manifest unknown — you're trying to push to a repository that doesn't exist and auto-create is disabled. Step 2: verify the service connection. Azure DevOps → Project Settings → Service connections → find your Docker registry connection → Test connection. If it fails: the service principal credentials may have expired. Step 3: check ACR permissions. In Azure Portal: the service principal used by the service connection must have AcrPush role on the specific ACR. Go to ACR → Access control (IAM) → check role assignments. Step 4: verify the registry URL and repository name in the pipeline task match exactly. A typo in the containerRegistry field or repository name causes authentication errors even if credentials are correct. Step 5: if using Managed Identity: confirm the pipeline agent's Managed Identity has AcrPush permission. Step 6: check ACR firewall. If ACR has network restrictions, the pipeline agent (Microsoft-hosted agent uses Azure datacenter IPs) may be blocked. Solution: add Azure DevOps service tag to ACR network rules, or use a self-hosted agent in the same VNet.
Continue Learning
🔵 Azure⚙️ Jenkins🏠 Home
🤖
AI Assistant
Ask anything about this topic
👋 Hi! I have read this page and can answer your questions.

Try asking: "Explain this topic in simple terms" or "Give me an example" or ask any specific question.