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:
- Write code on your laptop.
- Zip it up.
- SSH into the server.
- Cross your fingers and pray.
- 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:
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
# .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
| Problem | Cause | Fix |
|---|---|---|
| Different dependencies | CI installs fresh. Production has leftovers. | Docker everything. Immutable artifacts. |
| Different environment variables | CI has DEBUG=True. Prod doesn’t. | Use env: in GitHub Actions and match production secrets. |
| Database migrations forgot | Code deployed, migration not run. | Add a migration step BEFORE the deploy step. |
| Tests pass but app crashes | Tests 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.
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%.
Load Balancer
│
├──► v1 (90% traffic)
│
└──► v2 (10% traffic "Canary") ← Test on real users
Final Mental Model
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:
- Fast feedback: The pipeline should fail in under 5 minutes if there’s a problem.
- Everything is code: The pipeline config is in Git. No clicking in Jenkins UI.
- Immutable artifacts: Build once, deploy the same image everywhere. Never
git pullon a production server.
Related posts
-
Docker vs. Kubernetes: The 'Hotel Manager' Mental Model
Why do I need K8s if I have Docker? A mastery guide to understanding Containers (Robots) vs Orchestration (The Manager).
-
Observability: Logs vs. Metrics vs. Tracing — The 'Doctor's Kit' Mental Model
Your app is slow. Is it the DB? The queue? The network? A mastery guide to the three pillars of observability and how they work together.
-
Yellorn: The Browser Tab I Wanted for Dirty Data and Webhook Debugging
Tour Yellorn: repair broken JSON, XML, YAML, and CSV, publish mock webhooks, send HTTP requests — all private and local in your browser.
-
Production Google OAuth In One Prompt: I Let Cursor Drive Chrome DevTools MCP
I asked an AI agent to wire production Google OAuth. One prompt later it clicked through Cloud Console, configured scopes, and shipped to prod.