Scheduling ECS services to zero — safely
ECS has no "stop service" button. You scale a service to zero by setting desiredCount
to 0, and back up by restoring it. Simple in principle — but whether it saves anything depends on
your launch type, and Application Auto Scaling will happily undo it if you let it.
How you "stop" an ECS service
The action is update-service --desired-count 0. ECS drains the running tasks (respecting
deregistration delay on any attached target group) and stops them, while leaving the service and its
task definition in place. Bringing it back is update-service --desired-count N — so the
only state you must preserve across the cycle is the original count.
# OFF window: remember the current count, then drain to zero
CURRENT=$(aws ecs describe-services --cluster dev \
--services api --query 'services[0].desiredCount' --output text)
# stash CURRENT somewhere durable (a tag, SSM param, etc.) before zeroing
aws ecs update-service --cluster dev --service api --desired-count 0
# ON window: restore the stashed count
aws ecs update-service --cluster dev --service api --desired-count "$CURRENT"
Whether it saves money depends on the launch type
Fargate: you pay per running task. desiredCount = 0 means no tasks,
which means no Fargate compute charge. Scheduling the service directly saves money.
EC2 launch type: tasks run on EC2 container instances you provision. Setting the
service to zero frees the tasks but the EC2 instances keep running and billing. To save,
you must also scale in the capacity provider's Auto Scaling group. Scheduling the service alone
does nothing to the bill.
For EC2 launch type, treat the ECS service and its underlying ASG as one unit: zero the service, then scale the ASG (or let managed scaling drain it) in the same off-window. On Fargate there is no capacity layer to worry about — the task is the billable unit.
The Fargate math
Fargate on-demand (Linux/x86, us-east-1) bills $0.04048 per vCPU-hour and
$0.004445 per GB-hour. A common 2 vCPU / 4 GB task costs
(2 × 0.04048) + (4 × 0.004445) = $0.09874/hour. Run three of them around the clock
versus ~45 hours a week:
| Fargate service (2 vCPU / 4 GB tasks) | Per hour | Always-on / mo | Scheduled ~45 hr/wk |
|---|---|---|---|
| 1 task | $0.09874 | $71.09 | $19.06 |
| 3 tasks | $0.29622 | $213.28 | $57.17 |
Monthly figures are rate × 720 hours (always-on) and rate × ~193 hours
(~45 hours/week over a 30-day month). Scheduling the three-task service saves about
$156/month. Ephemeral storage beyond the included 20 GB and any data transfer are
separate and small.
The gotchas that break naive scheduling
-
Application Auto Scaling fights you. If a target-tracking or step policy with
MinCapacity > 0is attached, it overrides your manualdesiredCountand scales back up within minutes. Set the scalable target's minimum to zero as part of the off-window:
Restore the real min/max on the on-window before setting the count back.aws application-autoscaling register-scalable-target \ --service-namespace ecs \ --resource-id service/dev/api \ --scalable-dimension ecs:service:DesiredCount \ --min-capacity 0 --max-capacity 0 - Preserve the real desiredCount. Do not hardcode the restore value. Stash the pre-zero count durably (a tag or SSM parameter) so the on-window restores exactly what was there.
- Bring dependencies up in order. A service that talks to a database should come up after the database is available and go down before it — otherwise the on-window starts tasks that crash-loop against a cold DB. See stopping RDS on a schedule.
- What still bills at zero tasks. The ALB in front of the service, any NAT Gateway it egresses through, CloudWatch Logs, and ECR image storage all keep billing. Scaling to zero recovers task compute, not the surrounding infrastructure — schedule those separately.
Handling the count, the auto-scaling override, the stored original count, and the ordering — on a timezone-aware schedule — is what Uptime Scheduler runs for tagged ECS services inside your account.
FAQ
How do you stop an ECS service on a schedule?
Set desiredCount to 0 (there is no stop action); ECS drains and stops the tasks while
keeping the service. Restore the original count to bring it back.
Does scaling an ECS service to zero actually save money?
On Fargate, yes — no running tasks, no compute charge. On EC2 launch type, no — the container instances keep billing unless you also scale in the ASG behind the service.
Why does my ECS service scale back up after I set desiredCount to zero?
Application Auto Scaling with a non-zero minimum overrides the manual count. Set the scalable target's minimum to zero (or suspend the policy) to hold at zero.
See which services are idle overnight
upscan reports idle ECS services and their
cost — run upscan --resources ecs --region us-east-1. Free CLI, no signup; start from
what's measured.