Azure DevOps & CI/CD
In short: DevOps combines development and operations culture, practices and tools to deliver value faster and more reliably: automation, collaboration, small batches, fast feedback and monitoring.
- CI (Continuous Integration): developers merge frequently, and every change is automatically built and tested.
- CD: Continuous Delivery keeps every build releasable and deploys to production with a manual approval;
- Continuous Deployment deploys every passing change to production automatically.
In short: Azure Boards (work tracking, Kanban, sprints), Azure Repos (Git repos, PRs, branch policies), Azure Pipelines (CI/CD for any platform/cloud), Azure Test Plans (manual/exploratory testing), Azure Artifacts (package feeds).
- Available as Azure DevOps Services (cloud) and Azure DevOps Server (on-prem, formerly TFS).
In short: A pipeline has triggers, optional variables/parameters/resources, and stages (e.g. Build, DeployDev, DeployProd);
- each stage contains jobs that run on an agent;
- each job has steps — tasks (prebuilt, like
DotNetCoreCLI@2,AzureWebApp@1) or scripts. - Deployment jobs target environments with approvals.
- Artifacts pass outputs between stages.
In short: Classic build and release pipelines are configured in the web UI (release pipelines with stages, artifacts and gates).
- YAML pipelines are pipelines-as-code stored in the repo: versioned, reviewed in PRs, branchable, reusable via templates, and support multi-stage CI/CD with environments and checks.
- Microsoft recommends YAML; some classic features are being retired or disabled for new organisations.
In short: An agent is software on a machine that runs pipeline jobs.
- Microsoft-hosted agents are fresh VMs provided per job, preconfigured with common tools, no maintenance, but no private network access and cache isn't kept.
- Self-hosted agents run on your machines/containers: custom tools, persistent caches, access to on-prem/private resources, but you maintain and secure them.
- Managed DevOps Pools offer Microsoft-managed agents with private networking.
In short: Rules on protected branches (e.g. main) enforced on pull requests: require PRs, minimum reviewers, linked work items, resolved comments, successful build validation pipeline, required reviewers by path, allowed merge types, external status checks.
- They keep
mainalways buildable and reviewed, enforce quality gates, and create traceability.
In short: Store them as secret variables or in variable groups linked to Azure Key Vault (or fetch with the AzureKeyVault@2 task).
- Secrets are masked in logs and must be mapped explicitly into scripts via
env. - Use service connections with workload identity federation (no stored client secrets), restrict pipeline permissions on variable groups/service connections, add approvals, and never commit secrets to the repo (enable secret scanning).
In short: An environment represents a deployment target (dev, test, prod — or Kubernetes namespaces/VMs) with deployment history and traceability.
- Approvals and checks configured on the environment gate deployment jobs: manual approvers, branch control (only from main), business hours, Azure Monitor alert queries, REST/Function checks, exclusive lock (one deployment at a time), required templates.
- They replace classic release gates.
${{ }}, $[ ] and $( )?In short: ${{ }} are template (compile-time) expressions, evaluated when the YAML is parsed — used for parameters, conditional insertion and template logic.
$[ ]are runtime expressions evaluated before a job/stage runs — used in conditions and variables depending on other jobs' outputs.$( )is macro syntax replaced just before a task executes — used in task inputs and scripts.
In short: YAML templates (step, job, stage, variable templates) with typed parameters, stored in a shared repository referenced via resources.repositories;
extendstemplates to enforce a standard pipeline skeleton (with the required-template check on environments);- variable groups for shared settings;
- task groups in classic pipelines.
In short: For most web/cloud teams: trunk-based development or GitHub flow — short-lived branches, PRs with build validation, frequent merges to main, feature flags for incomplete work, automated deployment through environments with approvals.
- It reduces merge conflicts and supports CI/CD.
- GitFlow suits products with scheduled releases and multiple supported versions but adds overhead.
In short: Generate idempotent migration scripts in CI (dotnet ef migrations script --idempotent, SSDT DACPAC, or DbUp/Flyway scripts), publish them as artifacts, review them, apply in each environment's deployment stage before the app (SqlAzureDacpacDeployment@1, sqlcmd, EF migration bundle), using backward-compatible (expand/contract) changes so old and new app versions work during rollout.
- Back up / use point-in-time restore for rollback.
In short: PR pipeline: restore, build, unit tests, coverage, SonarQube, dependency and secret scanning, Docker build (no push), Bicep/Helm lint.
- Main pipeline: build and test → build image tagged with commit SHA → scan with Trivy/Defender → push to ACR → deploy to dev via Helm (or update a GitOps repo) → integration/smoke tests → staging with approval → canary or blue-green to production with automated health checks (App Insights/Prometheus) and automatic rollback.
- Use templates, workload-identity service connections, Key Vault secrets, environments with approvals, and track DORA metrics.
In short: Four key metrics from the DevOps Research and Assessment program: Deployment frequency, Lead time for changes (commit to production), Change failure rate (% of deployments causing failures), and Time to restore service (now often "failed deployment recovery time").
- They measure delivery performance; elite teams deploy on demand with low failure rates and fast recovery.
In short: Find the gap: missing tests (add integration/contract tests for the failure), environment differences (config, data, secrets — use the same artifact and IaC everywhere), no smoke tests (add post-deploy health checks that fail the stage), big-bang releases (use canary/blue-green or slot swaps with warm-up, feature flags), and no automatic rollback (monitor key metrics and roll back on alerts).
- Run a blameless post-mortem and add the fix to the pipeline.
In short: Measure each step.
- Then: cache NuGet/npm packages (
Cache@2), run independent jobs in parallel (split test projects), use incremental builds and only build changed services (path filters), use faster/self-hosted or Managed DevOps Pool agents with warm caches, avoid rebuilding — build once and promote the same artifact, move slow end-to-end tests to a nightly or post-merge stage, use Docker layer caching, and remove redundant steps.
Treat it as compromised: rotate the credential immediately (change password/key, or switch to managed identity), check access logs, remove it from the code and move it to Key Vault/variable groups, rewrite history only if required by policy (history may already be cloned), enable secret scanning/push protection (GitHub Advanced Security for Azure DevOps) and pre-commit hooks, and run a short blameless review on the process.
In short: Deploy to a staging slot, warm it up (application initialization / health check path), run smoke tests against the slot URL, then swap slots (the swap is instantaneous and warmed);
- keep slot-specific settings sticky;
- if issues appear, swap back.
- Combine with backward-compatible DB migrations and feature flags.