Introduction: The Modern CI/CD Stack
A modern full-stack CI/CD pipeline transforms code commits into production deployments in minutes, not days. The GitHub Actions + Docker + Azure stack has become the industry standard for teams building cloud-native applications — combining GitHub's native workflow automation, Docker's environment consistency, and Azure's enterprise-grade hosting infrastructure.
In 2025-2026, this stack powers over 80% of enterprise .NET and Node.js deployments. Teams using automated CI/CD pipelines deploy 46x more frequently with 5x lower change failure rates (DORA metrics). This guide covers the complete pipeline architecture — from workflow triggers through container builds to production deployment with zero-downtime rollouts.
GitHub Actions: Workflow Anatomy and Triggers
GitHub Actions workflows are YAML-defined automation pipelines triggered by repository events:
- Trigger Events: Configure workflows on
pushto main/release branches,pull_requestfor PR validation,schedulefor nightly builds, andworkflow_dispatchfor manual deployments — each trigger can filter by branch, path, and tag patterns. - Job Architecture: Define parallel jobs for frontend and backend — each job runs on
ubuntu-latestrunners with steps for checkout, dependency installation, testing, building, and deploying. Useneeds:for job dependencies. - Reusable Workflows: Extract common patterns into reusable workflows with
workflow_call— shared build/test/deploy templates that multiple repositories consume, ensuring consistency across teams. - Matrix Builds: Test across multiple Node.js versions (18, 20, 22) and .NET versions (8, 9) simultaneously —
strategy.matrixspawns parallel jobs for each combination, catching version-specific issues early. - Secrets Management: Store Azure credentials, Docker Hub tokens, and API keys in GitHub Secrets (repository or organisation level) — access with
${{ secrets.AZURE_CREDENTIALS }}syntax, never hardcoded in workflows.
Docker: Multi-Stage Builds and Image Optimisation
Docker containers ensure environment parity from development to production:
- Multi-Stage Builds: Separate build and runtime stages — the first stage compiles code with full SDKs (Node.js + npm, .NET SDK), the second copies only compiled output into a minimal runtime image (
node:20-alpineormcr.microsoft.com/dotnet/aspnet:8.0). Reduces image size by 60-80%. - Layer Caching: Order Dockerfile instructions from least to most frequently changed —
COPY package.jsonbeforeCOPY . .enables npm install caching. In GitHub Actions, usedocker/build-push-actionwithcache-from: type=ghafor cross-build caching. - Image Tagging: Tag images with
git SHA, semantic version, and environment —myapp:abc123f,myapp:v2.3.1,myapp:staging. Never use:latestin production to ensure deployment reproducibility. - Non-Root Users: Create a dedicated user in Dockerfile —
RUN adduser --disabled-password appuserandUSER appuser. Running as root in containers is a critical security vulnerability. - Health Checks: Add
HEALTHCHECK --interval=30s CMD curl -f http://localhost:3000/health— Docker and Azure use health checks for container lifecycle management and auto-restart on failure.
Azure Deployment: App Service, AKS, and Container Instances
Azure offers multiple deployment targets for containerised applications:
- Azure App Service: Simplest deployment — push Docker images to Azure Container Registry (ACR), configure App Service to pull from ACR. Supports deployment slots for blue-green deployments, auto-scaling rules, and custom domains with managed SSL certificates.
- Azure Kubernetes Service (AKS): For microservices architectures — deploy with Helm charts or Kustomize manifests. AKS provides auto-scaling (HPA + cluster autoscaler), service mesh (Istio/Linkerd), and rolling updates with configurable
maxSurgeandmaxUnavailable. - Azure Container Apps: Serverless container hosting — no cluster management, built-in Dapr integration for microservices communication, KEDA-based auto-scaling to zero, and revision-based traffic splitting for canary deployments.
- Deployment Slots: App Service deployment slots enable zero-downtime deployments — deploy to staging slot, run smoke tests, then swap with production. Auto-rollback if health checks fail within the warm-up period.
- Azure Container Registry: Store Docker images in ACR with geo-replication — enable vulnerability scanning with Microsoft Defender, image quarantine policies, and retention policies for unused images.
Security: Container Scanning and Supply Chain Protection
Security must be embedded into every pipeline stage:
- SAST (Static Analysis): Integrate CodeQL in GitHub Actions — scans source code for security vulnerabilities (SQL injection, XSS, path traversal) on every PR. CodeQL supports JavaScript, TypeScript, C#, Python, and Java.
- Container Scanning: Use Trivy or Snyk Container in the build pipeline — scan Docker images for OS-level vulnerabilities (CVEs in base images) and application dependency vulnerabilities. Fail builds on critical/high severity findings.
- Secret Scanning: Enable GitHub Advanced Security secret scanning — detects accidentally committed API keys, passwords, and tokens. Configure push protection to block commits containing secrets before they reach the repository.
- SBOM Generation: Generate Software Bill of Materials with
docker sbomor Syft — track every dependency in your container images for compliance and vulnerability response. - Image Signing: Sign container images with Cosign (Sigstore) — verify image integrity at deployment time, preventing supply chain attacks through tampered images. Azure ACR supports Notary v2 for native image signing.
Transform Your Publishing Workflow
Our experts can help you build scalable, API-driven publishing systems tailored to your business.
Testing: Unit, Integration, and E2E in CI
Comprehensive testing ensures deployment confidence:
- Unit Tests: Run Jest (frontend), xUnit/.NET Test (backend) as the first pipeline step — fast feedback on code correctness. Enforce minimum coverage thresholds (80%+) with
--coverageflags. - Integration Tests: Use Docker Compose in GitHub Actions to spin up dependent services (PostgreSQL, Redis, RabbitMQ) — test API endpoints against real databases. Service containers defined in workflow YAML with
services:block. - E2E Tests: Run Playwright or Cypress against the deployed staging environment — verify complete user flows (registration, checkout, search) with browser automation. Upload test artifacts (screenshots, videos) on failure.
- Performance Tests: Integrate k6 or Artillery load tests — validate response time SLAs (<200ms p95) and throughput thresholds before production promotion. Run against staging with realistic traffic patterns.
- Test Parallelisation: Shard large test suites across multiple runners using
strategy.matrix— split 500 tests into 5 parallel jobs of 100 tests each, reducing total pipeline time from 30 to 8 minutes.
Infrastructure as Code: Terraform and Bicep
Provision and manage Azure infrastructure reproducibly through code:
- Terraform: Define Azure resources (App Service, AKS, ACR, SQL Database, Key Vault) in HCL —
terraform planpreviews changes,terraform applyprovisions infrastructure. Store state in Azure Storage Account with state locking. - Bicep: Azure's native IaC language — compiles to ARM templates with cleaner syntax. Define modules for reusable infrastructure components (networking, compute, databases) with parameterised inputs.
- GitOps Workflow: Store IaC in the same repository as application code — trigger infrastructure changes through PR review. GitHub Actions runs
terraform planon PR, applies on merge to main. - Environment Parity: Use identical Terraform modules for dev, staging, and production — parameterise SKU sizes, replica counts, and feature flags. Prevent configuration drift between environments.
- Secrets Integration: Provision Azure Key Vault through IaC and inject secrets into App Service/AKS — application code reads secrets from Key Vault references, never from environment variables or config files.
Monitoring, Observability, and MDS DevOps Services
Production observability ensures rapid incident detection and resolution:
- Application Insights: Auto-instrument .NET and Node.js applications — track request rates, response times, failure rates, dependency calls, and custom events. Enable distributed tracing with correlation IDs across microservices.
- Azure Monitor: Create dashboards combining infrastructure metrics (CPU, memory, disk) with application metrics (request latency, error rates) — set alert rules for SLA violations with automated incident creation in PagerDuty or OpsGenie.
- Log Analytics: Centralise container logs in Azure Log Analytics workspace — query with KQL (Kusto Query Language) for debugging, performance analysis, and security investigation. Set log-based alerts for error patterns.
- Deployment Tracking: Annotate Application Insights with deployment markers — correlate performance changes with specific releases. Configure release gates that block production deployment if staging metrics degrade.
- Cost Monitoring: Use Azure Cost Management alerts and budgets — track CI/CD runner costs, container compute spend, and storage usage. Optimise with spot instances for non-production workloads.
MDS provides end-to-end DevOps engineering — designing CI/CD pipelines, containerising applications, provisioning Azure infrastructure with IaC, and implementing observability that ensures production reliability and rapid deployment cycles.



