How do resource requests and limits affect pod scheduling and QoS class?
Quick Answer
Requests reserve resources on a node (used by the scheduler for placement decisions). Limits cap maximum usage (enforced by the kernel via cgroups). Together, they determine the pod's QoS class: Guaranteed (requests=limits), Burstable (requests < limits), or BestEffort (no requests/limits). QoS class determines eviction priority when nodes run out of resources.
Detailed Answer
Think of requests and limits like airplane seat reservations. The request is your confirmed seat reservation -- the airline guarantees you that seat exists. The limit is the maximum overhead bin space you can use -- you can store luggage up to that amount, but security will stop you from exceeding it. If the airline overbooks (node memory pressure), passengers without reservations (BestEffort) are bumped first, then those with partial reservations (Burstable), and guaranteed-class passengers are bumped last.
Resource requests tell the Kubernetes scheduler how much CPU and memory a pod needs guaranteed. The scheduler only places a pod on a node if the node's allocatable resources minus all existing pod requests is greater than or equal to the new pod's requests. This is a hard constraint -- if no node has enough unrequested capacity, the pod stays Pending. Crucially, the scheduler does NOT look at limits or actual usage, only requests. This means a node can be 'full' from a scheduling perspective (all allocatable resources are requested) while actual utilization is only 30%.
Resource limits tell the kernel (via cgroups) the maximum a container can use. For CPU, exceeding the limit results in throttling -- the container is paused for the remainder of the cgroup period (typically 100ms). The container is NOT killed for exceeding CPU limits. For memory, exceeding the limit results in an OOM kill -- the kernel terminates the process immediately. This asymmetry is critical: CPU limits cause latency spikes, memory limits cause crashes.
The QoS class determines eviction priority during node memory pressure: (1) Guaranteed (requests == limits for all containers in the pod) -- lowest eviction priority, these pods are evicted last; (2) Burstable (at least one container has a request, but requests != limits) -- medium priority; (3) BestEffort (no requests or limits set on any container) -- highest eviction priority, evicted first. Within the Burstable class, pods using more memory relative to their request are evicted before those using less.
In production, the most common mistake is setting CPU limits too low. A pod with requests=100m and limits=200m will be throttled the instant it needs more than 200m, even if the node has 3 idle cores. Many teams now run without CPU limits entirely (only requests) to avoid artificial throttling while still allowing the scheduler to make good placement decisions. Memory limits remain essential because without them, a memory leak in one pod can OOM the entire node, killing all pods on it. The recommended pattern is: always set memory requests and limits (equal for critical services), always set CPU requests, and consider omitting CPU limits unless you need strict isolation.