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
| Concept | Description |
|---|---|
| Cluster | Logical grouping of tasks/services. No compute by itself. |
| Task Definition | Blueprint for a container (image, CPU, memory, env vars, ports, volumes). |
| Task | A running instance of a task definition. Ephemeral. |
| Service | Keeps N tasks running; integrates with ALB; handles rolling deploys. |
| EC2 Launch Type | You manage the EC2 instances in the cluster. |
| Fargate Launch Type | Serverless — AWS manages the underlying host. Pay per vCPU/GB/second. |
| ECS Anywhere | Run tasks on your own on-prem servers. |
| Container Instance | An 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
| Strategy | Config | Use Case |
|---|---|---|
| Rolling update | minimumHealthyPercent=50, maximumPercent=200 | Default; zero downtime |
| Blue/green | CodeDeploy integration | Instant rollback, canary |
| External | Any orchestrator | Full custom control |
# Enable blue/green via CodeDeploy
aws ecs create-service ... \
--deployment-controller Type=CODE_DEPLOYAuto 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:OpenDataChannelpermissions.
Fargate vs EC2 Launch Type
| Fargate | EC2 | |
|---|---|---|
| Host management | AWS | You |
| Pricing | Per task vCPU/GB/sec | Per EC2 instance-hour |
| Spot option | FARGATE_SPOT (~70% off) | Spot instances |
| Startup time | ~30s cold | Instance must be in cluster |
| Max task size | 16 vCPU / 120 GB | EC2 instance size |
| GPUs | No | Yes (p3, g4dn) |
| Best for | Microservices, APIs, batch | GPU workloads, max control |
Fargate Spot
aws ecs create-service ... \
--capacity-provider-strategy \
capacityProvider=FARGATE_SPOT,weight=4 \
capacityProvider=FARGATE,weight=1Use 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>