CI/CD Pipelines

Continuous Integration & Continuous Deployment

CI/CD Fundamentals

What is CI/CD?

Continuous Integration (CI)

Automatically build and test code changes frequently (multiple times per day).

Continuous Delivery (CD)

Code is always in deployable state. Manual approval for production.

Continuous Deployment (CD)

Fully automated - every change goes to production automatically.

Aspect CI Continuous Delivery Continuous Deployment
Build & Test Automated Automated Automated
Deploy to Staging Manual Automated Automated
Deploy to Production Manual Manual (approved) Automated
Deployment Frequency Varies Daily/Weekly Multiple per day

Benefits of CI/CD

Pipeline Stages

Typical CI/CD Pipeline

┌─────────────┐    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│   Commit    │───>│    Build    │───>│    Test     │───>│   Package   │───>│   Deploy    │
│  (Git Push) │    │  (Compile)  │    │(Unit, Integ)│    │  (Docker)   │    │  (Staging)  │
└─────────────┘    └─────────────┘    └─────────────┘    └─────────────┘    └─────────────┘
                                                                                      │
                                                                                      v
                                                                           ┌─────────────────┐
                                                                           │Manual Approval  │
                                                                           │ (for prod)      │
                                                                           └─────────────────┘
                                                                                      │
                                                                                      v
                                                                           ┌─────────────────┐
                                                                           │Deploy Production│
                                                                           └─────────────────┘

Stage 1: Source / Trigger

Stage 2: Build

Example (GitHub Actions):
name: Build
on: [push]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Lint
        run: npm run lint

      - name: Build
        run: npm run build

Stage 3: Test

- name: Run unit tests
  run: npm test -- --coverage

- name: Run integration tests
  run: npm run test:integration

- name: Security scan
  run: npm audit

- name: Upload coverage
  uses: codecov/codecov-action@v3

Stage 4: Package / Artifact Creation

- name: Build Docker image
  run: |
    docker build -t myapp:${{ github.sha }} .
    docker tag myapp:${{ github.sha }} myapp:latest

- name: Push to registry
  run: |
    echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
    docker push myapp:${{ github.sha }}
    docker push myapp:latest

Stage 5: Deploy

Build Optimization

1. Caching Dependencies

# GitHub Actions - Cache node_modules
- uses: actions/cache@v3
  with:
    path: ~/.npm
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-node-

# GitLab CI - Cache
cache:
  paths:
    - node_modules/
    - .npm/

Result: 5-minute build → 30-second build

2. Parallel Jobs

# Run tests in parallel
jobs:
  unit-tests:
    runs-on: ubuntu-latest
    steps:
      - run: npm test

  integration-tests:
    runs-on: ubuntu-latest
    steps:
      - run: npm run test:integration

  lint:
    runs-on: ubuntu-latest
    steps:
      - run: npm run lint

# All run simultaneously

3. Incremental Builds

4. Docker Layer Caching

# Use BuildKit for better caching
DOCKER_BUILDKIT=1 docker build .

# Use registry as cache
docker build --cache-from myapp:latest -t myapp:new .

Deployment Strategies

1. Blue-Green Deployment

Two identical environments. Switch traffic from old (blue) to new (green).

Before Deployment:
┌────────────┐
│   Users    │
└─────┬──────┘
      │
      v
┌─────────────┐      ┌─────────────┐
│ Load        │      │             │
│ Balancer    │      │             │
└──────┬──────┘      │             │
       │             │             │
       v             │             │
┌─────────────┐      │             │
│ Blue (v1.0) │      │ Green (idle)│
│ ████████    │      │             │
└─────────────┘      └─────────────┘

After Deployment (instant switch):
┌────────────┐
│   Users    │
└─────┬──────┘
      │
      v
┌─────────────┐      ┌─────────────┐
│ Load        │      │             │
│ Balancer    │      │             │
└──────┬──────┘      │             │
       │             │             │
       v             v             │
┌─────────────┐      ┌─────────────┐
│ Blue (v1.0) │      │ Green (v2.0)│
│ (idle)      │      │ ████████    │
└─────────────┘      └─────────────┘
Pros:
  • Instant rollback (switch back to blue)
  • Zero downtime
  • Full testing on green before switching
  • Simple to understand
Cons:
  • Requires 2x infrastructure
  • Database migrations tricky (must be backward compatible)
  • All-or-nothing switch

2. Canary Deployment

Roll out to small subset of users first. Gradually increase traffic if healthy.

Phase 1: 5% traffic to canary
┌────────────┐
│   Users    │
└─────┬──────┘
      │
      v
┌─────────────┐
│ Load        │ 95% ──> v1.0 (stable)
│ Balancer    │  5% ──> v2.0 (canary)
└─────────────┘

Phase 2: 50% traffic (if healthy)
┌─────────────┐
│ Load        │ 50% ──> v1.0
│ Balancer    │ 50% ──> v2.0
└─────────────┘

Phase 3: 100% traffic
┌─────────────┐
│ Load        │ 100% ─> v2.0
│ Balancer    │
└─────────────┘
Pros:
  • Reduces blast radius (only affects small % of users)
  • Gradual rollout
  • Real production traffic testing
  • Can roll back before affecting all users
Cons:
  • Slower rollout
  • Requires traffic splitting capability
  • Need good monitoring to detect issues
  • User experience may vary during rollout
# Kubernetes Canary with Flagger
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
  name: myapp
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: myapp
  service:
    port: 8080
  analysis:
    interval: 1m
    threshold: 5
    maxWeight: 50
    stepWeight: 10
  canaryAnalysis:
    metrics:
    - name: request-success-rate
      thresholdRange:
        min: 99
    - name: request-duration
      thresholdRange:
        max: 500

3. Rolling Deployment

Gradually replace instances one-by-one or in batches.

Step 1: Replace 1 instance
v1: [██] [██] [██] [  ]
v2: [  ] [  ] [  ] [██]

Step 2: Replace another
v1: [██] [██] [  ] [  ]
v2: [  ] [  ] [██] [██]

Step 3: Replace all
v1: [  ] [  ] [  ] [  ]
v2: [██] [██] [██] [██]
Pros:
  • No extra infrastructure needed
  • Gradual rollout
  • Can pause/abort mid-rollout
Cons:
  • Two versions running simultaneously
  • Slower than blue-green
  • Rollback means rolling forward to old version
# Kubernetes RollingUpdate
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 10
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 2        # Create 2 extra pods during update
      maxUnavailable: 1  # Max 1 pod unavailable at a time

4. Feature Flags / Dark Launch

Deploy code to production but keep features disabled. Enable for specific users.

// Feature flag example
if (featureFlags.isEnabled('newCheckout', user.id)) {
  return ;
} else {
  return ;
}

// Gradually increase percentage
featureFlags.setRolloutPercentage('newCheckout', 10);  // 10% of users
Benefits:
  • Decouple deployment from release
  • Test in production safely
  • A/B testing
  • Instant rollback (toggle off)
  • Gradual rollout by user segment

GitOps

What is GitOps?

Use Git as single source of truth for infrastructure and application config. Changes to Git automatically deployed.

Principles

  1. Declarative: Desired state described in Git (YAML, Terraform)
  2. Versioned & Immutable: Git history is audit trail
  3. Pulled Automatically: Agent pulls from Git, applies changes
  4. Continuously Reconciled: Actual state matches desired state
Traditional Push-based CD:
┌──────────┐       ┌──────────┐       ┌──────────┐
│   Git    │──────>│   CI     │──────>│  Cluster │
│  Commit  │       │ Pipeline │       │  (push)  │
└──────────┘       └──────────┘       └──────────┘

GitOps Pull-based:
┌──────────┐       ┌──────────┐       ┌──────────┐
│   Git    │<──────│  Agent   │<──────│  Cluster │
│  Commit  │       │ (ArgoCD) │       │  (pull)  │
└──────────┘       └──────────┘       └──────────┘
                   Polls Git every 3min,
                   applies if changed

GitOps Tools

Tool Description Use Case
Argo CD Declarative GitOps for Kubernetes Most popular, rich UI, multi-cluster
Flux GitOps operator for Kubernetes CNCF project, lightweight
Jenkins X CI/CD + GitOps for Kubernetes Full CI/CD platform
Terraform Cloud GitOps for infrastructure Infrastructure as Code

Example: Argo CD

# Application definition
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: myapp
spec:
  source:
    repoURL: https://github.com/org/repo
    targetRevision: main
    path: k8s/manifests
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      prune: true      # Delete resources not in Git
      selfHeal: true   # Auto-sync if drift detected
Benefits:
  • Audit trail: Git history shows who changed what
  • Rollback: Git revert = instant rollback
  • Disaster recovery: Cluster lost? Rebuild from Git
  • Multiple environments: Dev/staging/prod branches
  • Security: Cluster never exposed (pulls, not pushed to)

CI/CD Tools Comparison

Tool Hosting Pros Cons
GitHub Actions Cloud (SaaS) Integrated with GitHub, easy setup, marketplace Vendor lock-in, limited free minutes
GitLab CI/CD Cloud or Self-hosted Integrated with GitLab, powerful, free tier generous Steeper learning curve
Jenkins Self-hosted Very flexible, huge plugin ecosystem, free Complex setup, maintenance overhead, UI dated
CircleCI Cloud (SaaS) Fast, good caching, Docker support Expensive at scale, config can be complex
Travis CI Cloud (SaaS) Simple, good for open source Declining popularity, limited features
Azure Pipelines Cloud (SaaS) Integrated with Azure, generous free tier Complex YAML, Microsoft ecosystem

Best Practices

1. Pipeline as Code

Store pipeline config in Git with application code.

# .github/workflows/ci.yml (version controlled)
# .gitlab-ci.yml
# Jenkinsfile
Benefits: Versioned, reviewed, auditable

2. Fail Fast

Run fastest/cheapest checks first.

# Good order:
1. Lint (seconds, cheap)
2. Unit tests (seconds to minutes)
3. Build (minutes)
4. Integration tests (minutes)
5. E2E tests (10-30 minutes, expensive)

# Don't run expensive tests if lint fails!

3. Keep Pipelines Fast

4. Immutable Artifacts

# Build once
docker build -t myapp:abc123 .

# Deploy to environments with same image
# Dev:
docker run -e ENV=dev myapp:abc123

# Prod:
docker run -e ENV=prod myapp:abc123

5. Environment Parity

Dev, staging, prod should be as similar as possible.

6. Secrets Management

Never:
  • Commit secrets to Git
  • Hardcode credentials in pipeline
  • Store secrets in plain text
Do:
  • Use CI/CD platform secrets (GitHub Secrets, GitLab CI Variables)
  • Use secret managers (Vault, AWS Secrets Manager, Azure Key Vault)
  • Rotate secrets regularly
  • Least privilege (only give access to what's needed)
# GitHub Actions - Use secrets
- name: Deploy
  env:
    AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
    AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
  run: ./deploy.sh

7. Monitoring & Rollback

# Kubernetes - Health checks
livenessProbe:
  httpGet:
    path: /health
    port: 8080
  initialDelaySeconds: 30
  periodSeconds: 10

readinessProbe:
  httpGet:
    path: /ready
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 5

8. Branch Strategy

Trunk-Based Development

Git Flow (for scheduled releases)

Key Takeaways

Interview Tips