AWS for DevOps — ECS Services & Scaling
7.4 — ECS Services & Scaling
A task is a running instance of a task definition. A service ensures a desired number of tasks are always running, handles rolling updates, and integrates with load balancers.
Task vs Service
| Concept | What It Is | Analogy |
|---|---|---|
| Task | A single running container (or group) | A single process |
| Service | Maintains N tasks, replaces failures | A systemd service with Restart=always |
| Standalone task | Run once, no restart | A cron job |
Creating an ECS Service
$ aws ecs create-service \
--cluster production \
--service-name my-app \
--task-definition my-app:5 \
--desired-count 3 \
--launch-type FARGATE \
--network-configuration \
"awsvpcConfiguration={subnets=[subnet-abc123,subnet-def456],securityGroups=[sg-xyz789],assignPublicIp=DISABLED}" \
--deployment-configuration \
"maximumPercent=200,minimumHealthyPercent=100"
{
"service": {
"serviceName": "my-app",
"desiredCount": 3,
"runningCount": 0,
"status": "ACTIVE"
}
}
Rolling Update Configuration
| Parameter | Value | Meaning |
|---|---|---|
minimumHealthyPercent |
100 |
Never go below 3 running tasks (100% of desired) |
maximumPercent |
200 |
Can temporarily run up to 6 tasks during deployment |
Deployment of v2 (desired=3, min=100%, max=200%):
Step 1: Start 3 new tasks (v2)
┌──v1──┐ ┌──v1──┐ ┌──v1──┐ ┌──v2──┐ ┌──v2──┐ ┌──v2──┐
│ run │ │ run │ │ run │ │start │ │start │ │start │
└──────┘ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘
Step 2: v2 tasks pass health checks → stop v1 tasks
┌──v2──┐ ┌──v2──┐ ┌──v2──┐
│ run │ │ run │ │ run │
└──────┘ └──────┘ └──────┘
Updating a Service (Deploy New Version)
# Update to a new task definition revision
$ aws ecs update-service \
--cluster production \
--service my-app \
--task-definition my-app:6 \
--force-new-deployment
# Watch the deployment
$ aws ecs describe-services \
--cluster production \
--services my-app \
--query 'services[0].deployments[].{Status:status,Running:runningCount,Desired:desiredCount,TaskDef:taskDefinition}'
[
{ "Status": "PRIMARY", "Running": 2, "Desired": 3, "TaskDef": "...my-app:6" },
{ "Status": "ACTIVE", "Running": 1, "Desired": 0, "TaskDef": "...my-app:5" }
]
Auto-Scaling ECS Services
ECS uses Application Auto Scaling to scale the number of tasks:
# Step 1 — Register the ECS service as a scalable target
$ aws application-autoscaling register-scalable-target \
--service-namespace ecs \
--scalable-dimension ecs:service:DesiredCount \
--resource-id service/production/my-app \
--min-capacity 2 \
--max-capacity 10
# Step 2 — Create a target tracking scaling policy
$ aws application-autoscaling put-scaling-policy \
--service-namespace ecs \
--scalable-dimension ecs:service:DesiredCount \
--resource-id service/production/my-app \
--policy-name cpu-scaling \
--policy-type TargetTrackingScaling \
--target-tracking-scaling-policy-configuration '{
"TargetValue": 70.0,
"PredefinedMetricSpecification": {
"PredefinedMetricType": "ECSServiceAverageCPUUtilization"
},
"ScaleInCooldown": 300,
"ScaleOutCooldown": 60
}'
This says: keep average CPU at 70%. Scale out fast (60s cooldown), scale in slowly (300s cooldown).
Scaling Metrics
| Metric | Use When |
|---|---|
ECSServiceAverageCPUUtilization |
CPU-bound workloads (computation, image processing) |
ECSServiceAverageMemoryUtilization |
Memory-bound workloads (caching, data processing) |
ALBRequestCountPerTarget |
Web APIs (scale based on request volume) |
| Custom CloudWatch metric | Queue depth, custom business metrics |
Scheduled Scaling
# Scale up before business hours (Monday-Friday 8 AM)
$ aws application-autoscaling put-scheduled-action \
--service-namespace ecs \
--scalable-dimension ecs:service:DesiredCount \
--resource-id service/production/my-app \
--scheduled-action-name scale-up-morning \
--schedule "cron(0 8 ? * MON-FRI *)" \
--scalable-target-action MinCapacity=5,MaxCapacity=20
# Scale down at night (10 PM)
$ aws application-autoscaling put-scheduled-action \
--service-namespace ecs \
--scalable-dimension ecs:service:DesiredCount \
--resource-id service/production/my-app \
--scheduled-action-name scale-down-night \
--schedule "cron(0 22 ? * MON-FRI *)" \
--scalable-target-action MinCapacity=2,MaxCapacity=5
Circuit Breaker
ECS includes a deployment circuit breaker — if tasks keep failing, the deployment automatically rolls back:
$ aws ecs update-service \
--cluster production \
--service my-app \
--deployment-configuration \
"maximumPercent=200,minimumHealthyPercent=100,deploymentCircuitBreaker={enable=true,rollback=true}"
Listing and Monitoring Tasks
# List running tasks
$ aws ecs list-tasks --cluster production --service-name my-app
{
"taskArns": [
"arn:aws:ecs:ap-south-1:123456789012:task/production/abc123",
"arn:aws:ecs:ap-south-1:123456789012:task/production/def456",
"arn:aws:ecs:ap-south-1:123456789012:task/production/ghi789"
]
}
# Get task details
$ aws ecs describe-tasks \
--cluster production \
--tasks abc123 \
--query 'tasks[0].{Status:lastStatus,Health:healthStatus,IP:containers[0].networkInterfaces[0].privateIpv4Address}'
{
"Status": "RUNNING",
"Health": "HEALTHY",
"IP": "10.0.1.45"
}
Common Mistakes
| Mistake | Why It Hurts | Fix |
|---|---|---|
minimumHealthyPercent=0 |
All tasks go down during deployment | Set to 100% for zero-downtime deploys |
| No circuit breaker | Bad deploys keep retrying forever | Enable deploymentCircuitBreaker with rollback |
| Scaling in too fast | Sudden traffic spike → not enough tasks | Set ScaleInCooldown to 300+ seconds |
| Not monitoring task health | Unhealthy tasks serve traffic | Use ALB health checks + container health checks |
Quick Reference
| Task | Command |
|---|---|
| Create service | aws ecs create-service --cluster CLUSTER --service-name NAME --task-definition TD --desired-count N |
| Update service | aws ecs update-service --cluster CLUSTER --service NAME --task-definition TD:NEW |
| Scale manually | aws ecs update-service --cluster CLUSTER --service NAME --desired-count N |
| List tasks | aws ecs list-tasks --cluster CLUSTER --service-name NAME |
| Stop a task | aws ecs stop-task --cluster CLUSTER --task TASK_ARN |
Next → ECS + ALB