aws / aws/containers-roadmap

[ECS] [request]: Add cpuReservation parameter to separate scheduling from runtime limits

Open
#2,753 0 comments 3 reactions 1 assignee Claimed by @nikitadahiya View on GitHub
ECS Proposed
Dominant language
Shell
Stars
5.4k
Forks
334
PR merge metrics
No merged PRs in 30d

Description

### Community Note
* Please vote on this issue by adding a 👍 [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to the original issue to help the community and maintainers prioritize this request
* Please do not leave "+1" or "me too" comments, they generate extra noise for issue followers and do not help prioritize the request
* If you are interested in working on this issue or have submitted a pull request, please leave a comment

**Tell us about your request**

Add a `cpuReservation` parameter for ECS EC2 tasks to separate scheduling reservation from runtime CPU limits, similar to how `memoryReservation` and `memory` work today.

**Which service(s) is this request for?**

Amazon ECS (EC2 launch type)

**Tell us about the problem you're trying to solve. What are you trying to do, and why is it hard?**

I run 28 services on ECS EC2 with average CPU usage of 25% and occasional spikes to 50%. The current `cpu` parameter does two things simultaneously:

1. **Scheduling reservation** - ECS uses it to decide if a task fits on an instance
2. **Runtime hard limit** - The container cannot exceed this value

This creates an impossible trade-off:

**Option A - Set cpu limit for protection:**
```json
"cpu": 512
```
- ✅ Protects against one service saturating the instance
- ❌ Reserves 512 units even though average usage is ~100
- ❌ Scheduler thinks instance is "full" even with 75% CPU idle
- ❌ Forces 3x overprovisioning of instances

**Option B - No cpu limit for efficiency:**
```json
"cpu": null
```
- ✅ Services share CPU dynamically
- ❌ One attacked/buggy service can use 100% CPU and impact all neighbors
- ❌ Lose 5 services instead of 1 during an incident

**Why memory doesn't have this problem:**

Memory already has separate parameters:
```json
"memoryReservation": 256, // Scheduling
"memory": 1024 // Runtime limit
```

**Real-world impact:**

Current state (with protection):
- 6 instances × 2048 CPU units = 12,288 total
- Must set `cpu: 512` for protection
- Can place: 12,288 ÷ 512 = 24 services maximum
- Actual CPU usage: 25% (wasted capacity)
- Cost: $180/month

With cpuReservation:
- Same 6 instances
- Set `cpuReservation: 128` (scheduling), `cpu: 512` (limit)
- Can place: 12,288 ÷ 128 = 96 services
- Safe placement: ~50 services with bursting headroom
- **Cost reduction: 50%** (3 instances instead of 6)

**Are you currently working around this issue?**

No viable workaround exists:

1. **CPU shares only** (container-level cpu without task-level): No absolute limit, doesn't prevent saturation
2. **Overprovisioning**: Pay for 2-3x more instances than needed
3. **No limits**: Unacceptable risk for production environments

**Additional context**

- **Feature parity**: Kubernetes has this (requests vs limits) since inception
- **Consistency**: ECS already does this correctly for memory (memoryReservation/memory)
- **Related issue**: #1646 requested the same feature in Jan 2022 (no AWS response)
- **Use case**: Multi-tenant clusters where services have variable load but need protection

**Proposed solution:**
```json
{
"containerDefinitions": [{
"cpuReservation": 128, // ECS scheduler uses this for placement
"cpu": 512, // Runtime enforces this as hard limit
"memoryReservation": 256,
"memory": 1024
}]
}
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.