TL;DR: Requests drive scheduling and CPU weight under contention; limits cap runtime consumption. CPU quota can throttle, while failed memory reclaim at the cgroup limit can trigger OOM killing. For memory-pressure eviction, the kubelet ranks whether usage exceeds requests, then priority and relative excess. QoS is not a strict three-class eviction queue.
How to approach it
Separate the two audiences in the first sentence, because that framing makes everything else obvious. Then handle CPU and memory separately, since treating them the same is the main error.
A strong answer
Requests are a scheduling contract. The scheduler sums requests on each node and places your pod where the sum still fits allocatable capacity. Requests are not hard upper bounds, so a pod can use more if the node has room. CPU requests also influence cgroup shares/weight during contention. This is why a node can show 30 percent CPU usage and still refuse to schedule anything.
Limits are enforced by the kernel through cgroups, and the two resources behave differently.
CPU is compressible. A limit becomes a CFS quota: a limit of 1000m grants 100ms of CPU time per 100ms period. Exceed it and the process is not killed, it is frozen until the next period. This is why CPU limits cause latency spikes rather than failures, and why a multi-threaded runtime can burn its whole quota in a few milliseconds and then sit idle for the rest of the period. Diagnosed by comparing nr_throttled to nr_periods in the container's cpu.stat.
Memory is incompressible. The kernel can reclaim caches and other reclaimable memory. If an allocation cannot succeed within memory.max after reclaim, the cgroup can enter OOM handling and kill a process. Confirm OOMKilled and kernel/cgroup evidence; exit 137 alone only indicates a SIGKILL-derived exit status.
For ordinary container-level CPU and memory resources, QoS classification is:
| Class | Condition | Eviction interpretation |
|---|---|---|
| Guaranteed | CPU and memory requests equal their limits for every container | usually within requests, but not immune |
| Burstable | some CPU/memory request or limit, but not Guaranteed | rank depends on usage and priority |
| BestEffort | no CPU/memory requests or limits | nonzero usage exceeds zero request |
For memory pressure, over-request pods rank before those within requests, then priority and relative excess decide ordering. Disk-pressure eviction uses disk-related usage and requests; QoS does not encode ephemeral storage. Node-pressure eviction.
The opinionated part, and it is a live debate worth having in the interview: set memory limits, and think hard before setting CPU limits. Memory limits protect the node from one pod taking it down. CPU limits enforce an upper bound; requests influence contention weights but do not cap consumption, and they introduce throttling that hurts latency. Setting requests accurately and omitting CPU limits is a defensible position at many shops. Where you do need them is multi-tenant clusters where a noisy neighbour is a real risk.
What interviewers probe next
"Why did raising the CPU limit fix a latency problem?" Because you were throttled, not saturated. The fix reveals the cause.
"What is the node's allocatable versus capacity?" Capacity minus kube-reserved, system-reserved and eviction thresholds. Scheduling works against allocatable, which is why a 16-core node does not offer 16 cores.
"What does a LimitRange do?" Applies defaults per namespace so nothing ships as BestEffort by accident, which is the practical fix for the eviction-order problem at scale.
Common mistakes
Treating CPU and memory as symmetric. Throttled and killed are very different outcomes.
Setting limits equal to requests everywhere for "Guaranteed" without noticing you have also capped every burst.
Sizing requests from peak usage, which reserves capacity permanently for a spike that happens twice a day.