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.
Need a Custom Integration Built?
From Gmail Add-ons to full API integrations, our team delivers production-ready automation solutions tailored to your workflows.
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.



