12 min read Automation & Release Pipelines Part 3 (10 / 16)
Part 3 — CI/CD & IaC

Lesson 12.10 — How CI/CD & Automated Deployment Work

From Git Push to Production Live: GitHub Actions, automated testing, Docker image building, secure cloud SSH deployment, and zero-downtime release engineering.

What We Will Master in This Lesson

In earlier lessons, we manually logged into virtual machines, built Docker images, mapped domain names, and configured Nginx reverse proxies. However, in modern teams where multiple developers push code daily, manual releases lead to human errors and catastrophic outages. In this lesson, we master:

  • Manual vs. Automated Deployment across 7 critical dimensions
  • Continuous Integration (CI) mechanics & solving "Merge Hell"
  • The vital distinction between Continuous Delivery & Continuous Deployment
  • The 6 core pipeline building blocks (Repository, Trigger, Runner, Job, Step, Artifact)
  • GitHub Actions architecture & production-grade YAML workflow authoring
  • Cloud secrets management & automated SSH deployment to Ubuntu VMs
  • Zero-downtime release strategies: Recreate, Rolling, Blue-Green, and Canary
  • Health check failure detection & instant 3-second automated rollbacks
Modern Software Delivery

What is CI/CD? Revolutionizing Software Releases

Imagine you have built a simple web application. Initially, you had only a handful of features. You wrote code locally, transferred files to your cloud server via FTP, or SSHed into the host to run git pull.

As the product grew, a team of five developers joined. One develops authentication, another works on payment gateways, and a third refactors the database schema. With dozens of features and bug fixes landing daily, manual server updates become untenable: missing dependencies, inconsistent configurations, and untested edge cases will bring down production.

CI/CD (Continuous Integration and Continuous Delivery/Deployment): A set of unified engineering practices and automated toolchains where code changes undergo automated linting, testing, Docker image packaging, security audits, and production rollout with zero manual human friction.
CI: Continuous Integration

Developers merge code into a shared repository multiple times a day. Every pull request triggers an automated build and test runner to prove that new changes do not break existing functionality.

CD: Continuous Delivery / Deployment

Automates the packaging and release of validated software artifacts (such as Docker images) into staging or production cloud clusters—either upon one-click human approval or fully autonomously.

Deployment Comparison

Manual Deployment vs. Automated Deployment

In manual operations, an engineer must execute a fragile checklist of terminal commands late at night:

The Fragility of Manual Deployments:
1. ssh ubuntu@203.0.113.10
2. cd /var/www/my-app && git pull origin main
3. npm install (network timeouts or package discrepancies)
4. npm run build (exhausting host memory during compilation)
5. npx prisma migrate deploy (forgotten or out-of-order schema migrations)
6. pm2 restart app / docker restart (10-second downtime gap)
7. Manually refreshing the browser to see if the site crashed...
Dimension Manual Deployment Automated Deployment (CI/CD)
Code Updates Engineers manually type terminal commands Triggered automatically on Git Push events
Automated Testing Frequently skipped due to time pressure 100% required; broken tests block rollout
Build Environment Compiled directly on live production VMs Built in clean, ephemeral cloud runners
Human Error Risk Extremely high (typos, forgotten steps) Near zero (deterministic, coded workflows)
Release Speed 30 minutes to multiple hours 2 to 5 minutes
Rollback Facility Panic-prone, high downtime Instant revert to prior semantic tag in seconds
Consistency Varies by engineer and time of day Identical execution 24/7/365
Integration Mechanics

How Continuous Integration (CI) Works

In legacy engineering teams, developers suffered from an affliction known as "Merge Hell". Engineers worked on isolated branches for weeks. At month-end, attempting to merge hundreds of diverged files caused irreconcilable conflicts, regression bugs, and days of troubleshooting.

Continuous Integration solves this directly: *"Do not accumulate changes for weeks. Merge small, incremental commits into the mainline branch multiple times daily, and verify each merge with automated builds and tests."*

1

Local Development & Pre-Commit Verification

Developers write features and verify unit tests pass locally.

2

Git Commit & Remote Push

Code is pushed to a feature branch on GitHub and a Pull Request is opened.

3

Automated CI Runner Provisioning (Trigger)

GitHub spins up a pristine virtual machine, checks out the code, and configures runtimes.

4

Linting, Unit Testing & Build Compilation

Linter checks formatting, security analyzers scan dependencies, and unit tests run in parallel.

5

Feedback & Status Gate

A green checkmark ✓ appears on the PR if all stages pass, granting merge readiness. Any failure halts the pipeline immediately.

Clarifying Terminology

Continuous Delivery vs. Continuous Deployment: The Essential Difference

The acronym "CD" represents two distinct release paradigms. Both rely on automated testing and artifact packaging, but they differ in whether a Human Approval Gate precedes production rollout:

Continuous Delivery Manual Gate

Software is continuously tested, packaged, and maintained in an always-releasable state. Deployments to staging occur automatically. However, triggering the production release requires an explicit human action (such as an approval click by a release manager).

Code Push → Test → Build → Staging → [Manual Approval] → Production
Continuous Deployment 100% Automated

Every commit that successfully clears automated quality and security gates is automatically released to production without human intervention. Within minutes of merging, real users interact with the new code.

Code Push → Test → Build → Quality Gate → [Auto Deploy] → Production
When to choose which?

Regulated industries (Fintech, Healthcare, Banking) where compliance audits and scheduled release windows are legally mandated typically employ Continuous Delivery. Consumer web and modern SaaS platforms (like Netflix, GitHub, or Vercel) with mature test suites rely on Continuous Deployment to push hundreds of micro-releases every day.

Pipeline Anatomy

The 6 Core Components of Every CI/CD Pipeline

Regardless of whether you choose GitHub Actions, GitLab CI, or Jenkins, all production pipelines share these six foundational architectural components:

1. Source Code Repository

The central version control store (GitHub, GitLab, Bitbucket) that tracks commit history and acts as the event source for automation.

2. Trigger Events

Events that initiate pipeline runs: code pushes, pull requests, release tagging, schedule cron jobs, or manual webhooks.

3. Runners (Execution Environments)

Compute nodes executing the pipeline jobs: cloud-managed Hosted Runners or organization-managed Self-hosted Runners.

4. Jobs (Work Units)

Logical collections of steps (e.g., test, build, deploy) that run in parallel or sequentially using needs: dependencies.

5. Steps (Atomic Tasks)

Sequential commands executed inside a job: checking out code, installing Node.js, and running test suites.

6. Artifacts (Immutable Outputs)

Compile outputs preserved across pipeline stages or deployed to registries—such as binary packages, coverage reports, or Docker Images.

Industry-Standard Toolchain

How GitHub Actions Works: Practical YAML Workflow Structure

GitHub Actions is the industry standard for modern cloud development because it lives directly inside the Git repository without requiring separate automation server infrastructure.

Workflow definitions are stored as YAML files inside the .github/workflows/ directory of your project.

.github/workflows/build-and-publish.yml YAML
name: Build, Test & Publish Docker Image

# 1. Triggers
on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

permissions:
  contents: read

jobs:
  # 2. Test and Build Job
  build-and-test:
    runs-on: ubuntu-latest

    steps:
      # Step 1: Clone repository onto the runner
      - name: Checkout Code
        uses: actions/checkout@v4

      # Step 2: Validate integrity of source files
      - name: Validate Source Files
        run: test -s site/index.html && echo "Source files intact."

      # Step 3: Setup Docker Buildx engine
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      # Step 4: Login to Docker Hub (only on push to main)
      - name: Login to Docker Hub
        if: github.event_name == 'push' && github.ref == 'refs/heads/main'
        uses: docker/login-action@v3
        with:
          username: $
          password: $

      # Step 5: Build and push tagged Docker image
      - name: Build and Push Docker Image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
          tags: |
            $/my-website:$
            $/my-website:latest
Why Commit SHA Tagging Matters: Notice that we do not rely solely on :latest. We tag every image with $. If an unexpected bug arises in production, we know with 100% certainty the exact commit hash that produced the running container!
Environments & Security

Staging vs. Production Environments & Cloud Secrets Management

Before releasing to real users, artifacts are validated in a mirror environment known as Staging:

Staging Environment (Testbed)

An exact architectural replica of production where QA engineers and stakeholders perform acceptance tests using sanitized test data.

Production Environment (Live Traffic)

The mission-critical live system serving real users, customer transactions, and sensitive business data. Requires strict approval controls and automated rollback mechanisms.

GitHub Secrets: Safeguarding Keys and Credentials

Never hardcode passwords or SSH private keys into your Git repository! GitHub Actions provides encrypted credential storage via Settings → Secrets and variables → Actions:

Secret Identifier Operational Purpose Security Best Practice
DOCKERHUB_TOKEN Access token for publishing images to Docker Hub Use scoped Read/Write Personal Access Tokens rather than root passwords
DEPLOY_HOST Public IP of target Cloud Virtual Machine (203.0.113.10) Avoids hardcoding mutable IP addresses in workflow scripts
DEPLOY_USER Dedicated deployment user account on the Linux VM Avoid root execution; use a dedicated deployer user with scoped sudo privileges
DEPLOY_SSH_KEY OpenSSH Private Key (id_ed25519) for server authentication Ensures non-interactive, passwordless key authentication
SSH_KNOWN_HOSTS Verified public server host key fingerprint Prevents Man-in-the-Middle (MITM) host spoofing during automated connections
Production Workflow

Complete Production Two-Job CI/CD Deployment Workflow

Below is a complete, enterprise-ready two-job pipeline. The first job (build) creates and tags the Docker image, and the second job (deploy) connects to our Ubuntu Cloud VM via SSH to update the live container:

.github/workflows/deploy.yml YAML
name: Build and Deploy to Cloud VM

on:
  push:
    branches: [ main ]

jobs:
  # ==========================================
  # JOB 1: Build & Publish Docker Image
  # ==========================================
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v4

      - name: Validate Source
        run: test -s site/index.html

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: $
          password: $

      - name: Build and Push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: $/my-website:$

  # ==========================================
  # JOB 2: Remote Deployment via SSH
  # ==========================================
  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment: production

    steps:
      # 1. Setup SSH credentials on the ephemeral runner
      - name: Configure SSH Agent & Keys
        env:
          DEPLOY_KEY: $
          KNOWN_HOSTS: $
        run: |
          install -m 700 -d ~/.ssh
          printf '%s\n' "$DEPLOY_KEY" > ~/.ssh/id_ed25519
          chmod 600 ~/.ssh/id_ed25519
          printf '%s\n' "$KNOWN_HOSTS" > ~/.ssh/known_hosts
          chmod 600 ~/.ssh/known_hosts

      # 2. Connect to remote host and update container
      - name: Execute Remote Deployment via SSH
        env:
          HOST: $
          USER: $
          IMAGE_NAME: $/my-website
          TAG: $
        run: |
          ssh "$USER@$HOST"             "sudo docker pull ${IMAGE_NAME}:${TAG} &&
             (sudo docker rm -f my-website >/dev/null 2>&1 || true) &&
             sudo docker run -d \
               --name my-website \
               --restart unless-stopped \
               -p 127.0.0.1:8080:80 \
               ${IMAGE_NAME}:${TAG}"

      # 3. Automated health check verification
      - name: Verify Live Health Status
        env:
          HOST: $
        run: |
          curl --fail --retry 3 --retry-delay 5 https://example.com/ || exit 1
          echo "Deployment verified healthy on production!"
Eliminating Downtime

How to Eliminate Downtime During Deployment: 4 Core Strategies

In the basic single-server example, stopping the container before starting the new one creates a temporary gap where users see 502 Bad Gateway. In high-traffic systems, zero-downtime is maintained through four primary deployment strategies:

1. Recreate Deployment Has Downtime

Terminates all existing instances before booting new ones. Simple and resource-efficient, but produces downtime during the restart window.

2. Rolling Deployment Zero Downtime

Updates instances incrementally one by one. Once a new pod passes health checks, traffic is routed to it and the next old pod is replaced.

3. Blue-Green Deployment Instant Cutover

Maintains two identical production environments: Blue (active) and Green (idle). The new release is verified on Green, and the router/load balancer instantly flips 100% traffic to Green.

4. Canary Deployment Risk-Free Rollout

Routes a small percentage of real user traffic (e.g., 5%) to the new version. Telemetry is monitored for latency and error spikes before expanding to 100%.

Best Practices

7 Golden Rules for Building Reliable CI/CD Pipelines

1. Commit small and often: Merge small, frequent commits into the main branch rather than large monthly feature branches.
2. Never merge without automated tests: Mandatory unit and smoke test suites act as strict gates in every pull request.
3. Build once, deploy anywhere: Compile a single immutable Docker image in CI and promote that identical image across Staging and Production.
4. Strict secret hygiene: Never commit secrets or private keys into source code; store them exclusively in encrypted Secrets Managers.
5. Optimize pipeline execution speed: Maintain total pipeline runtime under 10 minutes using Docker layer caching and parallel jobs.
6. Automated health checks & rollback: A release is unverified until /health responds 200 OK. Immediately revert to prior commit SHA images upon failure.
7. Pipeline as Code: Store pipeline definitions inside Git alongside application source code to ensure complete versioning and auditability.
Interactive Simulator

CI/CD & Automated Release Workbench

Test real-time pipeline execution, deployment strategy traffic switching, workflow generation, and automated rollback across four interactive tabs:

Live Pipeline Execution from Git Push to Cloud VM

Step through the pipeline to inspect real-time terminal output at each stage:

Pipeline Progress Stage 1/5 (20%)
GitHub Actions Runner Console RUNNING
Initializing GitHub-hosted runner (ubuntu-latest)...
Key Takeaways & What's Next

What We Mastered in This Lesson

Preparing for the Next Challenge

Lesson 12.11 — Infrastructure as Code (IaC) with Terraform

We have automated application code testing, container building, and server deployment. But what about the underlying cloud virtual machines, VPC networks, security groups, and storage buckets? Manually clicking in cloud provider web dashboards is error-prone and unscalable. In the next lesson, we master Infrastructure as Code (IaC) using Terraform, provisioning entire cloud ecosystems in code with a single command!

References & Supplemental Resources: