Pod Priority and Preemption
What happens when an important Pod has nowhere to fit on a full cluster? Its PriorityClass resolves to a numeric priority, and when every Node fails on capacity the Scheduler preempts, unless that class sets preemptionPolicy Never. It picks a minimal set of lower-priority Pods whose removal makes room and deletes the bound ones with a plain DELETE, not an eviction, so a PodDisruptionBudget is honoured only best effort. The Pod is then bound in their place.
Play the animation 5 steps, animated, best on a wide screen
Pod Priority and Preemption, step by step
-
Pod NEW arrives at the API. The Priority admission plugin resolves spec.priorityClassName to a number, system-cluster-critical being 2000000000, and writes it into spec.priority. That plugin rejects a spec.priority differing from the one it computed, so with the plugin enabled, as it is by default, PriorityClass is the only route. The other built-in class, system-node-critical, is slightly higher.
Play from step 1 -
Scheduler takes Pod NEW off its queue and runs a scheduling cycle. Filter plugins drop every Node failing a predicate (taints, ports, requests against allocatable), and here all of them fail on capacity. Before that failure is recorded, the default preemptionPolicy=PreemptLowerPriority opens preemption mode. A class set to Never would leave Pod NEW queued as Unschedulable.
Play from step 2 -
Preemption scans the running Pods on each Node for a minimal victim set whose deletion lets Pod NEW fit, every victim at strictly lower priority, the more important ones reprieved first. Pod A at 100 is enough alone: freeing its 1 CPU and 1Gi memory matches the Pod NEW requests. Pod B at 1000, the most important candidate, is the first one reprieved. Pod C ties at 100 but started earlier, so it is tried before Pod A and kept.
Play from step 3 -
Scheduler patches Pod A with a DisruptionTarget condition, reason PreemptionByScheduler, then sends a standard DELETE, not an eviction, so PodDisruptionBudget gates are bypassed, though victim choice prefers PDB-friendly sets. Pod A enters Terminating for its terminationGracePeriodSeconds: preStop, SIGTERM, SIGKILL. In a separate status write Pod NEW is recorded Unschedulable with status.nominatedNodeName=Node-1, reserved but not guaranteed: a higher priority Pod can still take it.
Play from step 4 -
Pod A exited gracefully, its capacity back on Node-1. Scheduler retries Pod NEW on its nominated Node first, Filter passes, and it binds to Node-1. The controller owning Pod A creates a replacement, scheduled elsewhere or left Pending. This is not node-pressure eviction, covered separately, where Kubelet ranks by over-request first, then Priority, then how far over the request each sits.
Play from step 5