Command Palette

Search for a command to run...

Hectal
PHASE 5Intermediate ~13 min· topic 1 of 4

Topic 5.1

ECR & ECS on Fargate

In one line

ECR stores your container images; ECS runs them as tasks described by a task definition and kept alive by a service — and with Fargate, AWS provides the compute for each task so there are no EC2 nodes to manage.

0/4 · 0%

Think of it like this

ECR is the warehouse holding your packaged meals (images). ECS is the restaurant kitchen manager: a TASK DEFINITION is the recipe card, a SERVICE is the standing order 'always keep 4 of these plates ready', and FARGATE is a catering company that supplies the stoves on demand so you never buy kitchen equipment.

Key ideas

  1. 01

    ECR is a private Docker registry per account/region. Enable scan-on-push for vulnerability findings, use IMMUTABLE tags so :1.4.2 can never be overwritten, and add lifecycle policies to delete old untagged images. Tag images with the git SHA, not just latest.

  2. 02

    A TASK DEFINITION is a versioned JSON spec: container images, CPU/memory, ports, environment variables, secrets (pulled from Secrets Manager/SSM at start), log configuration, and two roles — the EXECUTION ROLE (used by ECS to pull the image and fetch secrets) and the TASK ROLE (the permissions your application code gets). Mixing up these two is the most common ECS IAM mistake.

  3. 03

    A SERVICE keeps N tasks running, registers them with an ALB target group (Phase 2.4), replaces failed tasks, and performs rolling deployments. Enable the DEPLOYMENT CIRCUIT BREAKER with rollback so a new version that keeps failing health checks automatically reverts.

  4. 04

    FARGATE vs EC2 launch type: Fargate means no instances to patch, scale, or bin-pack — you pay per task vCPU/GB-second. The EC2 launch type (a cluster of instances you manage, via capacity providers) is cheaper at high steady utilization and needed for GPUs or special instance types. Fargate Spot offers up to ~70% off for interruptible work.

  5. 05

    Each Fargate task gets its own ENI and private IP in your subnets (awsvpc mode), so security groups apply per task. Services can scale with target tracking on CPU, memory, or ALB requests per target, exactly like an ASG.

Code & diagrams

push-to-ecr.shbash
REPO=123456789012.dkr.ecr.ap-south-1.amazonaws.com/api
aws ecr create-repository --repository-name api \
  --image-tag-mutability IMMUTABLE --image-scanning-configuration scanOnPush=true

aws ecr get-login-password --region ap-south-1 | \
  docker login --username AWS --password-stdin 123456789012.dkr.ecr.ap-south-1.amazonaws.com

SHA=$(git rev-parse --short HEAD)
docker build -t $REPO:$SHA .
docker push $REPO:$SHA
task-definition.jsonjson
{
  "family": "api",
  "requiresCompatibilities": ["FARGATE"],
  "networkMode": "awsvpc",
  "cpu": "512",
  "memory": "1024",
  "runtimePlatform": { "cpuArchitecture": "ARM64", "operatingSystemFamily": "LINUX" },
  "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecution",
  "taskRoleArn": "arn:aws:iam::123456789012:role/api-task",
  "containerDefinitions": [
    {
      "name": "api",
      "image": "123456789012.dkr.ecr.ap-south-1.amazonaws.com/api:3f9c2ab",
      "portMappings": [{ "containerPort": 8080 }],
      "environment": [{ "name": "NODE_ENV", "value": "production" }],
      "secrets": [
        { "name": "DB_URL", "valueFrom": "arn:aws:secretsmanager:ap-south-1:123456789012:secret:prod/db-url" }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/api",
          "awslogs-region": "ap-south-1",
          "awslogs-stream-prefix": "api"
        }
      }
    }
  ]
}
ecs-service.shbash
aws ecs register-task-definition --cli-input-json file://task-definition.json

aws ecs create-service --cluster prod --service-name api \
  --task-definition api --desired-count 3 --launch-type FARGATE \
  --network-configuration 'awsvpcConfiguration={subnets=[subnet-a,subnet-b],securityGroups=[sg-app],assignPublicIp=DISABLED}' \
  --load-balancers targetGroupArn=$API_TG,containerName=api,containerPort=8080 \
  --deployment-configuration 'deploymentCircuitBreaker={enable=true,rollback=true},minimumHealthyPercent=100,maximumPercent=200'

# Deploy a new revision
aws ecs update-service --cluster prod --service api --task-definition api:42

# Shell into a running task (ECS Exec, uses SSM under the hood)
aws ecs execute-command --cluster prod --task <task-id> --container api --interactive --command sh

Explain it without notes

01

What's the difference between an ECS task's execution role and its task role?

02

What does the deployment circuit breaker protect you from?

Practice

01

A task fails to start with ResourceInitializationError: unable to pull secrets. What do you check?

02

Your service runs 40 tasks at steady 70% utilization 24/7. Would you keep Fargate? What would you consider?

Trade-offs

  • ↔

    Fargate removes node management, patching, and bin-packing, and isolates each task, but costs more per unit of compute than well-utilized EC2 and doesn't support GPUs or privileged containers.

Done when you can

  • I push images to ECR with immutable, commit-SHA tags.

  • I can write a Fargate task definition and know which role does what.

  • I run services behind an ALB with the circuit breaker and rollback enabled.

  • I can decide between Fargate and the EC2 launch type for a workload.