Featured image of post CI/CD Pipeline: The 'Factory Assembly Line' Mental Model

CI/CD Pipeline: The 'Factory Assembly Line' Mental Model

Why does 'works on my machine' still happen with Docker? A mastery guide to CI/CD pipelines, GitHub Actions, and zero-downtime Blue/Green deployments.

Every team starts with the same deployment process:

  1. Write code on your laptop.
  2. Zip it up.
  3. SSH into the server.
  4. Cross your fingers and pray.
  5. Something breaks in production at 2 AM.

CI/CD exists to make Step 3–5 automatic, repeatable, and less terrifying.

This is the Mastery Guide to CI/CD. We’ll use the “Factory Assembly Line” model to understand pipelines, GitHub Actions, and the art of zero-downtime deployments.


Part 1: Foundations (The Mental Model)

The Old Way: Artisan Crafting

In a blacksmith shop, one guy does everything: heats the metal, shapes it, cools it, inspects it, packages it. If he’s sick, nothing ships. If he makes a mistake, it goes to the customer.

This is manual deployment.

The New Way: The Factory Assembly Line

A modern factory has stations: Stamping → Welding → Painting → Inspection → Packaging. Each station checks the output of the previous one. If Inspection fails, nothing reaches Packaging.

This is CI/CD:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
Code Commit
[Station 1: CI — Continuous Integration]
    ├── Run Tests (Did we break anything?)
    ├── Lint Code (Is the code clean?)
    └── Build Docker Image (Does it even compile?)
[Station 2: CD — Continuous Delivery]
    ├── Push Image to Registry
    └── Deploy to Staging Environment
[Station 3: CD — Continuous Deployment]  ← (Optional: fully automated)
    └── Deploy to Production

Part 2: The Investigation (GitHub Actions Anatomy)

GitHub Actions is the most popular CI/CD tool for developers. A “workflow” is just a YAML file in .github/workflows/.

Reading a Pipeline

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# .github/workflows/deploy.yml

name: "Build and Deploy"

# TRIGGER: When does this run?
on:
  push:
    branches: [main]   # Only on pushes to main

jobs:
  # JOB 1: The CI (Test & Build)
  build:
    runs-on: ubuntu-latest  # What machine to run on (GitHub provides this)
    
    steps:
      - name: "Checkout Code"
        uses: actions/checkout@v4  # Built-in Action: Pull the code

      - name: "Run Tests"
        run: |
          pip install -r requirements.txt
          pytest tests/ --tb=short

      - name: "Build Docker Image"
        run: docker build -t myapp:${{ github.sha }} .

      - name: "Push to Registry"
        run: |
          docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }}
          docker push ghcr.io/myrepo/myapp:${{ github.sha }}

  # JOB 2: The CD (Deploy) — Only runs if build succeeds
  deploy:
    needs: build  # ← This job WAITS for build to pass
    runs-on: ubuntu-latest
    
    steps:
      - name: "Deploy to Server"
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: deploy
          key: ${{ secrets.SSH_KEY }}
          script: |
            docker pull ghcr.io/myrepo/myapp:${{ github.sha }}
            docker stop myapp || true
            docker run -d --name myapp -p 8000:8000 ghcr.io/myrepo/myapp:${{ github.sha }}

Key Concepts to Spot:

  • on: — The trigger. (push, pull_request, schedule).
  • jobs: — Independent units of work that CAN run in parallel.
  • needs: — Creates a dependency (Job B waits for Job A).
  • secrets: — Secrets stored in GitHub settings. Never hardcode passwords in YAML!

Part 3: The Diagnosis (Common Failures)

The “Works in CI, Fails in Production” Mystery

ProblemCauseFix
Different dependenciesCI installs fresh. Production has leftovers.Docker everything. Immutable artifacts.
Different environment variablesCI has DEBUG=True. Prod doesn’t.Use env: in GitHub Actions and match production secrets.
Database migrations forgotCode deployed, migration not run.Add a migration step BEFORE the deploy step.
Tests pass but app crashesTests don’t cover the startup code.Add a smoke test: curl http://localhost:8000/health after deploy.

Part 4: The Resolution (Deployment Strategies)

Not all deployments are equal. The strategy determines the risk.

Strategy 1: Rolling Deployment (Kubernetes Default)

Replace old pods one by one. Minimal risk. If one fails, stop.

Strategy 2: Blue/Green Deployment (Zero Downtime)

Run TWO identical production environments. “Blue” is live. “Green” is the new version.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Load Balancer
      ├──► Blue (v1) ← LIVE (100% traffic)
      └──► Green (v2) ← Staging (0% traffic)

After deploy:
      ├──► Blue (v1) ← Idle (0% traffic)
      └──► Green (v2) ← LIVE (100% traffic)
  • Benefit: Instant rollback. If Green fails, flip the switch back to Blue.
  • Cost: Requires double the infrastructure.

Strategy 3: Canary Deployment (Progressive)

Slowly roll out to a percentage of users. If no errors, increase to 100%.

1
2
3
4
5
Load Balancer
      ├──► v1 (90% traffic)
      └──► v2 (10% traffic "Canary") ← Test on real users

Final Mental Model

1
2
3
4
5
6
7
CI (Continuous Integration) -> The Quality Inspection. "Does this code compile and pass tests?"
CD (Continuous Delivery)    -> The Packaging. "Is this artifact ready to be deployed?"
CD (Continuous Deployment)  -> The Shipping. "Deploy automatically to production."

Blue/Green   -> Two factories. Instant switch.
Canary       -> Test on 10% of real customers first.
Rolling      -> Replace workers one by one.

Rules for Good CI/CD:

  1. Fast feedback: The pipeline should fail in under 5 minutes if there’s a problem.
  2. Everything is code: The pipeline config is in Git. No clicking in Jenkins UI.
  3. Immutable artifacts: Build once, deploy the same image everywhere. Never git pull on a production server.
Made with laziness love 🦥

Subscribe to My Newsletter