Skip to main content

Set resource requests and limits

Inspect 1.36

Most resource advice says to match both limits to the request on every container and call the pod Guaranteed. Follow it here and you introduce latency you never needed. The right default is narrower: cap memory at its request, leave CPU uncapped, land as Burstable. A request is what the scheduler reserves, a limit the ceiling. Treat them the same and you ignore that CPU and memory fail differently.

Tip

Memory limit equal to the request, no CPU limit, Burstable. Right for most workloads. Go beyond it only when you can name why.

Set a CPU and memory request on every container. A request-less container looks free to the scheduler, so it packs onto a full node and gets evicted under pressure, and free to the , so a pod that should trigger a scale-up silently never does.

Why the CPU limit stays off#

CPU is throttled, not killed. A CPU limit is an absolute CFS quota: hit it and the kernel slows the container even when the node has idle cores, latency in exchange for nothing. The request already sets a guaranteed floor, so let the pod burst into spare CPU. Add a CPU limit only to fence a proven noisy neighbour.

Memory is the opposite. It cannot be reclaimed by slowing a container down, so a container that grows past its request with no limit starves the node and gets its neighbours OOM-killed. Cap the limit at the request to hold it to what it reserved; if it needs more, raise both numbers rather than dropping the limit.

QoS follows from your requests#

Kubernetes derives each pod's QoS class from its requests and limits, and that class decides who the kubelet evicts first under memory pressure:

Class When Under pressure
Guaranteed every container has requests equal to limits, CPU and memory evicted last
Burstable at least one request set, but not Guaranteed evicted after BestEffort
BestEffort no requests or limits at all evicted first

That combination lands you in Burstable, protected on memory and free on CPU. Use Guaranteed only when a workload demands it, such as a database that pins cores with whole-integer CPU requests equal to limits.

Node capacity is not the whole machine#

The scheduler places against a node's allocatable capacity, not its physical size. The platform reserves CPU and memory for system daemons, holds back an eviction buffer, and caps pods per node. See for the figures. Never size a pool as if every byte were schedulable.

Right-size from real usage#

Guessing requests wastes money high and triggers evictions low. Measure instead: the recommends requests from history.