AWS Cheatsheet

ECS and Fargate

Use this AWS reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

Core Concepts

ConceptDescription
ClusterLogical grouping of tasks/services. No compute by itself.
Task DefinitionBlueprint for a container (image, CPU, memory, env vars, ports, volumes).
TaskA running instance of a task definition. Ephemeral.
ServiceKeeps N tasks running; integrates with ALB; handles rolling deploys.
EC2 Launch TypeYou manage the EC2 instances in the cluster.
Fargate Launch TypeServerless — AWS manages the underlying host. Pay per vCPU/GB/second.
ECS AnywhereRun tasks on your own on-prem servers.
Container InstanceAn EC2 instance running the ECS agent (EC2 launch type only).

Clusters

# Create Fargate cluster
aws ecs create-cluster \
  --cluster-name my-cluster \
  --capacity-providers FARGATE FARGATE_SPOT

# List clusters
aws ecs list-clusters
aws ecs describe-clusters --clusters my-cluster

# Delete (must drain tasks first)
aws ecs delete-cluster --cluster my-cluster

Task Definitions

# Register from JSON file
aws ecs register-task-definition --cli-input-json file://task-def.json

# List task definitions
aws ecs list-task-definitions --family-prefix my-app
aws ecs describe-task-definition --task-definition my-app:3

# Deregister (retire old revisions)
aws ecs deregister-task-definition --task-definition my-app:1

Minimal Fargate Task Definition

{
  "family": "my-app",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "256",
  "memory": "512",
  "executionRoleArn": "arn:aws:iam::123:role/ecsTaskExecutionRole",
  "taskRoleArn":      "arn:aws:iam::123:role/my-app-task-role",
  "containerDefinitions": [{
    "name": "app",
    "image": "123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app:latest",
    "portMappings": [{"containerPort": 3000, "protocol": "tcp"}],
    "environment": [
      {"name": "NODE_ENV", "value": "production"}
    ],
    "secrets": [
      {"name": "DB_PASSWORD", "valueFrom": "arn:aws:secretsmanager:us-east-1:123:secret:db-pass"}
    ],
    "logConfiguration": {
      "logDriver": "awslogs",
      "options": {
        "awslogs-group":         "/ecs/my-app",
        "awslogs-region":        "us-east-1",
        "awslogs-stream-prefix": "ecs"
      }
    },
    "healthCheck": {
      "command":  ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"],
      "interval": 30,
      "timeout":  5,
      "retries":  3
    }
  }]
}

Run a One-Off Task

aws ecs run-task \
  --cluster my-cluster \
  --task-definition my-app:3 \
  --launch-type FARGATE \
  --network-configuration '{
    "awsvpcConfiguration": {
      "subnets": ["subnet-0priv1","subnet-0priv2"],
      "securityGroups": ["sg-0abc123"],
      "assignPublicIp": "DISABLED"
    }
  }'

# Wait for task to stop
aws ecs wait tasks-stopped --cluster my-cluster --tasks arn:aws:ecs:...

# Get exit code
aws ecs describe-tasks \
  --cluster my-cluster \
  --tasks arn:aws:ecs:... \
  --query 'tasks[0].containers[0].exitCode'

Services

# Create service (Fargate, behind ALB)
aws ecs create-service \
  --cluster my-cluster \
  --service-name my-svc \
  --task-definition my-app:3 \
  --desired-count 2 \
  --launch-type FARGATE \
  --network-configuration '{
    "awsvpcConfiguration": {
      "subnets": ["subnet-0priv1","subnet-0priv2"],
      "securityGroups": ["sg-0abc123"],
      "assignPublicIp": "DISABLED"
    }
  }' \
  --load-balancers '[{
    "targetGroupArn": "arn:aws:elasticloadbalancing:...",
    "containerName": "app",
    "containerPort": 3000
  }]' \
  --deployment-configuration \
    minimumHealthyPercent=100,maximumPercent=200

# Update service (new image or desired count)
aws ecs update-service \
  --cluster my-cluster \
  --service my-svc \
  --task-definition my-app:4 \
  --desired-count 3

# Force a new deployment (re-pull :latest)
aws ecs update-service \
  --cluster my-cluster \
  --service my-svc \
  --force-new-deployment

# Wait for stable
aws ecs wait services-stable --cluster my-cluster --services my-svc

# Scale to zero
aws ecs update-service \
  --cluster my-cluster \
  --service my-svc \
  --desired-count 0

# Describe
aws ecs describe-services --cluster my-cluster --services my-svc
aws ecs list-services --cluster my-cluster

# Delete
aws ecs delete-service --cluster my-cluster --service my-svc --force

Deployment Strategies

StrategyConfigUse Case
Rolling updateminimumHealthyPercent=50, maximumPercent=200Default; zero downtime
Blue/greenCodeDeploy integrationInstant rollback, canary
ExternalAny orchestratorFull custom control
# Enable blue/green via CodeDeploy
aws ecs create-service ... \
  --deployment-controller Type=CODE_DEPLOY

Auto Scaling

# Register ECS service as scalable target
aws application-autoscaling register-scalable-target \
  --service-namespace ecs \
  --resource-id service/my-cluster/my-svc \
  --scalable-dimension ecs:service:DesiredCount \
  --min-capacity 1 \
  --max-capacity 20

# Target tracking (keep avg CPU at 60%)
aws application-autoscaling put-scaling-policy \
  --service-namespace ecs \
  --resource-id service/my-cluster/my-svc \
  --scalable-dimension ecs:service:DesiredCount \
  --policy-name cpu-target-tracking \
  --policy-type TargetTrackingScaling \
  --target-tracking-scaling-policy-configuration '{
    "TargetValue": 60.0,
    "PredefinedMetricSpecification": {
      "PredefinedMetricType": "ECSServiceAverageCPUUtilization"
    },
    "ScaleInCooldown": 60,
    "ScaleOutCooldown": 30
  }'

ECR — Container Registry

# Create repository
aws ecr create-repository --repository-name my-app

# Authenticate Docker to ECR
aws ecr get-login-password --region us-east-1 | \
  docker login --username AWS --password-stdin \
  123456789012.dkr.ecr.us-east-1.amazonaws.com

# Build, tag, push
docker build -t my-app .
docker tag my-app:latest 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app:latest
docker push          123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app:latest

# List images
aws ecr list-images --repository-name my-app
aws ecr describe-images --repository-name my-app \
  --query 'imageDetails[*].[imageTags[0],imagePushedAt,imageSizeInBytes]' \
  --output table

# Lifecycle policy (keep only last 10 images)
aws ecr put-lifecycle-policy \
  --repository-name my-app \
  --lifecycle-policy-text '{
    "rules":[{
      "rulePriority":1,
      "description":"Keep last 10",
      "selection":{"tagStatus":"any","countType":"imageCountMoreThan","countNumber":10},
      "action":{"type":"expire"}
    }]
  }'

# Enable image scanning on push
aws ecr put-image-scanning-configuration \
  --repository-name my-app \
  --image-scanning-configuration scanOnPush=true

aws ecr delete-repository --repository-name my-app --force

Exec into Running Task (ECS Exec)

# Enable execute-command on service
aws ecs update-service \
  --cluster my-cluster \
  --service my-svc \
  --enable-execute-command

# Shell into container
aws ecs execute-command \
  --cluster my-cluster \
  --task arn:aws:ecs:... \
  --container app \
  --interactive \
  --command "/bin/sh"

Task role needs ssmmessages:CreateControlChannel + ssmmessages:CreateDataChannel + ssmmessages:OpenControlChannel + ssmmessages:OpenDataChannel permissions.

Fargate vs EC2 Launch Type

FargateEC2
Host managementAWSYou
PricingPer task vCPU/GB/secPer EC2 instance-hour
Spot optionFARGATE_SPOT (~70% off)Spot instances
Startup time~30s coldInstance must be in cluster
Max task size16 vCPU / 120 GBEC2 instance size
GPUsNoYes (p3, g4dn)
Best forMicroservices, APIs, batchGPU workloads, max control

Fargate Spot

aws ecs create-service ... \
  --capacity-provider-strategy \
    capacityProvider=FARGATE_SPOT,weight=4 \
    capacityProvider=FARGATE,weight=1

Use FARGATE as fallback. Handle SIGTERM + drain connections within 2 minutes on interruption.

Useful Logs Commands

# Stream logs for a service
aws logs tail /ecs/my-app --follow

# Get logs for a specific task
aws logs get-log-events \
  --log-group-name /ecs/my-app \
  --log-stream-name ecs/app/<task-id>