Node Pressure Eviction
In plain English
Plain definition
Kubernetes node-pressure eviction is the kubelet's response when memory, disk space, inodes or process IDs cross configured thresholds. It ranks pods for eviction to recover the node before it becomes unusable; incorrect requests, missing ephemeral-storage limits or sustained pressure can produce repeated disruption.
The kubelet runs a dedicated eviction manager control loop, polling cAdvisor/cgroup stats on a configurable interval (evictionPressureTransitionPeriod, default 5m) against a set of node-level signals: memory.available, nodefs.available, nodefs.inodesFree, imagefs.available, imagefs.inodesFree, and pid.available. Each signal can be configured with a hard threshold (immediate eviction, no grace period) and a soft threshold (eviction only after the condition persists beyond a configured grace period, e.g. evictionSoftGracePeriod). Crossing a threshold sets a corresponding node condition (MemoryPressure, DiskPressure, PIDPressure), which the scheduler reads to taint the node and stop placing new pods there, independent of whether any eviction has actually occurred yet.
Eviction ordering is deterministic and layered, not random: the kubelet first partitions pods by QoS class (BestEffort, then Burstable, then Guaranteed are evicted in that order for the resource under pressure), and within a class ranks pods by how far their actual usage exceeds their resource requests (usage-to-request ratio), with priorityClassName acting as a tiebreaker. This means a Burstable pod consuming far above its declared request can be evicted ahead of a BestEffort pod with negligible usage — QoS class dictates the eviction tier, but usage-over-request dictates ranking inside the tier. minReclaim settings force the manager to reclaim beyond the threshold itself to avoid immediately re-triggering the same eviction cycle, a common source of eviction ‘thrashing’ when misconfigured.
A critical architectural nuance is the race between kubelet-level eviction and the Linux kernel’s OOM killer. If memory pressure spikes faster than the eviction manager’s polling interval can react, the kernel invokes its own OOM killer based on oom_score_adj, which the kubelet pre-assigns per QoS class (Guaranteed gets the most negative score, BestEffort the least). This is why hard memory thresholds must be set with sufficient headroom above system-reserved/kube-reserved allocations — without that buffer, the kernel OOM killer preempts the kubelet’s orderly eviction, producing outcomes that ignore priority classes entirely since the kernel has no concept of Kubernetes scheduling priority.
Operationally, node pressure eviction interacts directly with PodDisruptionBudgets and controller reconciliation: evicted pods are not gracefully drained through the eviction API subresource (unlike kubectl drain) but are killed directly by the kubelet, meaning PDBs offer no protection against node-pressure evictions — only against voluntary disruptions initiated through the Eviction API. This distinction is frequently missed in capacity planning, leading teams to assume PDB-guaranteed availability that does not hold under genuine resource starvation. Correctly tuning this mechanism — soft/hard thresholds, grace periods, reserved capacity, and QoS assignment via requests/limits — is what determines whether resource contention on a shared node degrades gracefully or cascades into unpredictable, kernel-driven pod loss.