Eviction Order on a Memory-Pressured Node
A four-node cluster runs nodes with 16 GiB RAM each; DaemonSets already request about 5 GiB per node, leaving roughly 11 GiB of allocatable memory for application pods. Three Deployments are running:
web: 6 replicas, requests 2 GiB, limits 4 GiB, currently using 3.5 GiB eachcache: 2 replicas, requests 3 GiB, limits 3 GiB, currently using 3.0 GiB eachbatch: 4 replicas, no requests and no limits, currently using 2.5 GiB each
During a nightly batch spike one node reports MemoryPressure and the kubelet begins evicting pods. At the same time a newly created web pod stays Pending with the event 0/4 nodes are available: 4 Insufficient memory, even though kubectl top nodes shows 3 GiB of unallocated physical memory on two of them.
1. Which pods on the pressured node will the kubelet evict first, and why? The platform lead argues `web` should go first because it consumes the most memory. Evaluate that claim.
Read the worked answer
Eviction order is driven by QoS class first, then usage relative to request:
batchis BestEffort (no requests, no limits) and is evicted first, in order of largest memory usage among BestEffort pods.webis Burstable (requests < limits). Burstable pods are ranked by how far their usage exceeds their request - here 3.5 GiB used against a 2 GiB request, a 1.75x ratio.cacheis Guaranteed (requests == limits for every container) and is evicted last, and in practice only under severe pressure.
The lead's claim is wrong on two counts. Absolute consumption is not the ranking key - cache uses more per pod than nothing else in the Burstable tier and is still safest. And eviction protects the node, not the workload's business value: batch looks "small" but is the cheapest to lose from the kubelet's point of view, which may still be the wrong business outcome. If batch matters, give it requests and limits so it stops being BestEffort, and if web must survive pressure, raise its requests to equal its limits to move it into Guaranteed - at the cost of schedulability, since a 3.5 GiB request per pod is much harder to place than a 2 GiB one.
2. An engineer proposes: "Raise every container's memory limit to 8 GiB so nothing gets OOMKilled again." What is wrong with this as a fix for the symptoms described?
Read the worked answer
Three separate mechanisms are being conflated.
- Container OOMKill is a cgroup limit event: the container exceeds its own
limits.memoryand the kernel kills the process inside it. Raising limits does reduce this, but it does nothing for the node-level problem. - Node eviction is what is actually happening here (
MemoryPressure). It is driven by node allocatable memory and pod QoS class, and raising limits while leaving requests alone makes the node more overcommitted, not less. The sum of limits can legitimately exceed node capacity; that is normal overcommit, but it means limits are not a capacity guarantee. - Scheduling uses requests only. If the engineer raises limits without requests, schedulability is unchanged and the node pressure gets worse; if they raise requests too, most of these pods will stop fitting at all.
The durable fix is to set requests from observed steady-state usage (for web, somewhere near 2.5-3 GiB rather than 2 GiB), keep limits modestly above requests for burst headroom, and give batch real requests so it is neither BestEffort nor an invisible consumer of node memory. Also configure eviction thresholds and consider priority classes if some workloads must outrank others.
3. Explain why a `web` pod is `Pending` with `Insufficient memory` while `kubectl top nodes` reports free physical memory, and what an operator should look at first.
Read the worked answer
The scheduler does not read kubectl top. It filters nodes using sum of pod requests against node allocatable, after subtracting the kubelet's reserved capacity. top reports actual working sets, so the two numbers answer different questions: a node can have 3 GiB of genuinely free RAM and still have zero requested headroom, because pods have reserved memory they are not currently using.
What to check, in order:
kubectl describe node <node>- look atAllocated resourcesfor memory requests versus allocatable, and at theInsufficient memorytaint/condition.- Whether the pod's request (2 GiB for
web) exceeds the largest free request slot on any node. Requests are atomic per pod - the scheduler does not split a pod across nodes - so 3 GiB free spread as 2 x 1.5 GiB places nothing. - Whether DaemonSet requests are consuming far more than the assumed 5 GiB.
Mitigations are: lower the request if 2 GiB is inflated, enable the descheduler or rebalance, add a node, or use a topology/preemption-aware PriorityClass so a critical pod can preempt a lower-priority one. Reducing the container's usage will never move a Pending pod; only requests and allocatable matter.