AWS for DevOps — ECS Services & Scaling

3 minute read

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

Updated: