devuplabs.cloud
Free previewArchitecture note8 min read

GitHub → ECS Flow

Every component from GitHub push to running ECS tasks, source control, CI/CD, Docker, ECR, ECS, ALB, IAM, and CloudWatch in one end-to-end map.

Deployment Pipeline: Code → Production

Developer pushes code to GitHub
GitHub detects push (webhook)
GitHub Actions workflow triggered
Build stage: Compile, test, lint
Build Docker image
Push to ECR (Docker registry)
Update ECS task definition (new image URI)
ECS service detects new task definition
Rolling deployment: drain old tasks, start new ones
Application running on new code
CloudWatch monitors health
If unhealthy: auto-rollback to previous version

All Components Involved

Source Control (GitHub)

plain text
Your code lives here
├─ main branch (production)
├─ dev branch (development)
└─ feature branches (work in progress)

When you push to main:
└─ GitHub webhook fires → tells GitHub Actions "something changed"

GitHub Actions (CI/CD Orchestration)

plain text
Listens for webhook from GitHub
            ↓
Runs workflow file: .github/workflows/deploy.yml
            ↓
Workflow defines jobs:
├─ Build: compile, test, lint
├─ Docker: create image
├─ Push: upload to ECR
└─ Deploy: update ECS

Example workflow file:

yaml
name: Deploy to ECS

on:
  push:
    branches: [main]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3

      - name: Run tests
        run: npm test

      - name: Build Docker image
        run: docker build -t rds-course:latest .

      - name: Push to ECR
        run: |
          aws ecr get-login-password | docker login --username AWS --password-stdin $ECR_URL
          docker tag rds-course:latest $ECR_URL/rds-course:$GITHUB_SHA
          docker push $ECR_URL/rds-course:$GITHUB_SHA

      - name: Update ECS task definition
        run: |
          aws ecs update-service \
            --cluster production \
            --service rds-course-service \
            --task-definition rds-course:NEW_REVISION

Docker (Containerization)

plain text
Dockerfile: Recipe for your application
├─ Start from base image (node:18, python:3.11, etc.)
├─ Copy code into image
├─ Install dependencies
├─ Build/compile
└─ Set startup command

Result: Immutable artifact (Docker image)
└─ Same image runs everywhere: dev, staging, prod

Example Dockerfile:

docker
FROM node:18-alpine

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

COPY . .

EXPOSE 3000
CMD ["node", "server.js"]

ECR (Elastic Container Registry)

plain text
AWS's Docker image storage
└─ Like Docker Hub but for your private company images

When GitHub Actions pushes image:
├─ Authenticates to ECR (via IAM role)
├─ Uploads image layers
├─ Tags with: timestamp, git commit hash, "latest"
└─ Stores versioned images (never delete old ones)

Later: ECS pulls from ECR when launching tasks

ECS (Elastic Container Service)

plain text
Orchestrator that runs Docker containers at scale

Components:
├─ Cluster: logical grouping of EC2 instances or Fargate
├─ Task Definition: blueprint (Docker image, CPU, memory, ports, env vars)
├─ Service: keeps desired number of tasks running
│  └─ If a task dies, service launches a new one
└─ Task: running instance of the application

Deployment flow:
└─ You update task definition with new image URI
   ├─ ECS detects change
   ├─ Stops old tasks (gracefully drains connections)
   ├─ Launches new tasks with new image
   └─ Updates load balancer routing

ALB (Application Load Balancer)

plain text
Routes incoming traffic to healthy tasks

Flow:
├─ User request → ALB
├─ ALB checks: which tasks are healthy?
├─ Routes to healthy task
├─ During deployment:
│  ├─ Old tasks: connection draining (30s to finish existing requests)
│  ├─ New tasks: warm up (health checks pass)
│  └─ Traffic switches seamlessly
└─ No downtime

IAM Roles (Authentication)

plain text
GitHub Actions needs permissions:
├─ Read code from GitHub
├─ Push to ECR
└─ Update ECS service

ECS tasks need permissions:
├─ Read secrets from Secrets Manager
├─ Write logs to CloudWatch
└─ Pull images from ECR

Each component gets minimal permissions (least privilege)

CloudWatch (Monitoring)

plain text
Collects metrics + logs

During deployment:
├─ Old tasks: logs redirect to CloudWatch
├─ New tasks: logs stream immediately
├─ Metrics tracked:
│  ├─ CPU utilization
│  ├─ Memory usage
│  ├─ Request count
│  └─ Error rate

If error rate spikes:
└─ Alarm triggers → auto-rollback (optional)

Simplified Diagram

plain text
Developer (You)
    ↓
    ↓ git push main
    ↓
GitHub (Code repo)
    ↓
    ↓ webhook: "code changed"
    ↓
GitHub Actions (CI/CD)
    ├─ Runs tests
    ├─ Builds Docker image
    └─ Pushes to ECR
         ↓
         ↓ docker push image:v123
         ↓
ECR (Image registry)
         ↓
         ↓ "new image available"
         ↓
ECS Service
    ├─ Old Task 1: ❌ Stop (graceful drain)
    ├─ Old Task 2: ❌ Stop
    ├─ New Task 1: ✅ Start (new image)
    ├─ New Task 2: ✅ Start
    └─ Health check: pass → add to ALB
         ↓
         ↓ Route traffic
         ↓
ALB (Load Balancer)
         ↓
         ↓ HTTP/HTTPS
         ↓
Internet (Users)

Deployment Strategies

Rolling Deployment (Most common)

plain text
Before:
Task 1 (old) → ALB → User
Task 2 (old) → ALB → User
Task 3 (old) → ALB → User

During:
Task 1 (old) → ALB ✅ still routing
Task 2 (new) ↓ starting...
Task 3 (new) ↓ starting...

After:
Task 1 (new) → ALB → User
Task 2 (new) → ALB → User
Task 3 (new) → ALB → User

Zero downtime ✅
Gradual rollout ✅
Can rollback mid-deployment ✅

Blue-Green Deployment

plain text
Before:
Blue environment (old code)
├─ Task 1, 2, 3 running
└─ ALB routing to Blue

During:
Green environment (new code)
├─ Task 1, 2, 3 running (parallel)
└─ Running health checks

After:
ALB switches: Blue → Green
├─ Instant cutover
├─ Old Blue environment stays running (instant rollback available)
└─ If bad: switch back to Blue instantly

Zero downtime ✅
Instant rollback ✅
Needs double resources ❌ (expensive)

Canary Deployment

plain text
Before:
All tasks running old code

During:
Send 10% traffic to new code
├─ Monitor error rate
├─ If error rate < threshold: continue
├─ Else: stop, rollback

90% → old code
10% → new code

Monitor 5 minutes...

50% → old code
50% → new code

Monitor 5 minutes...

0% → old code
100% → new code ✅

Catches bugs early ✅
Gradual rollout ✅
Complex setup ❌

Key Concepts You Need to Understand

Task Definition (ECS)

plain text
A template that says:
├─ Use this Docker image
├─ Allocate this much CPU (256, 512, 1024 units)
├─ Allocate this much memory (512MB, 1GB, 2GB)
├─ Map port 3000 (container) to 80 (ALB)
├─ Environment variables (DATABASE_URL, etc.)
├─ Log configuration (CloudWatch)
└─ Secrets (Secrets Manager references)

When you deploy:
└─ You create NEW task definition revision
   (old one stays around for rollback)

Desired Count

plain text
ECS Service: "I want 3 tasks running at all times"

If one task dies:
└─ Service launches a new one (auto-healing)

During deployment:
├─ Old: 3 tasks (old image)
├─ New: 1 task (new image). ALB health check
├─ If healthy: stop 1 old, start 1 new
├─ Repeat until: 0 old, 3 new
└─ Desired count always = 3 ✅

Health Checks

plain text
ALB asks: "Is this task healthy?"

Task has an HTTP endpoint: /health
└─ Returns 200 OK if ready

ALB checks every 10 seconds:
├─ Task responsive? Yes → route traffic
├─ Task responsive? No → remove from routing

During deployment:
├─ New task starts
├─ Fails health checks (5-10 tries)
├─ Finally passes
├─ ALB adds to rotation
└─ Old task can now drain safely

Connection Draining

plain text
Old task receives shutdown signal

Before draining:
├─ ALB stops sending NEW requests
├─ Old task finishes existing requests (max 30s)
└─ Task shuts down cleanly

Result: No in-flight request loss ✅

Common Pitfalls

Task Definition Not Updated

plain text
❌ You push new code
❌ GitHub Actions runs
❌ Docker image pushed to ECR
❌ But you forgot to update task definition
❌ ECS still using old image
❌ Users don't see your new code

Fix: Always update task definition in workflow

No Rollback Plan

plain text
❌ Deploy new code
❌ 10 minutes later: users report bugs
❌ You scramble to fix code
❌ 30 minutes of downtime

Fix: Keep previous task definition
└─ In ECS console: click "Rollback to previous revision"
└─ Takes 2 minutes

Health Check Too Strict

plain text
❌ Health check URL: /health
❌ New code takes 15 seconds to boot
❌ ALB times out after 10 seconds
❌ Task fails health check
❌ Never routes traffic to new task
❌ Deployment stuck

Fix: Increase health check timeout or fix code startup time

Not Running Tests in CI

plain text
❌ Push broken code to GitHub
❌ GitHub Actions doesn't run tests
❌ Broken code deployed to production
❌ Users affected

Fix: Always run tests before Docker build

Unlock all 24 AWS services & 291+ lab sessions (~180 hours)

Pricing