Pod Scheduling Gates
Why has the Scheduler not even tried to place a Pod created a minute ago? Because spec.schedulingGates holds it out of the active queue: kubectl prints STATUS SchedulingGated, the PodScheduled condition is False with reason SchedulingGated, and scheduler_pending_pods counts it under queue gated rather than unschedulable. Entries come off in any order and none can be added after creation, so the Pod joins the active queue only once the list is empty.
Play the animation 6 steps, animated, best on a wide screen
Pod Scheduling Gates, step by step
-
A Pod is created with two entries in spec.schedulingGates, and while they stand the Scheduler makes no attempt to place it. Each entry is an opaque criterion that some other component owns. A gate can only be set while the Pod is being created, by the client that posts it or by an admission plugin that mutates it on the way in.
Play from step 1 -
While the list holds any entry the Pod never enters the active queue, so the Scheduler runs no cycle on it and no Node is ever filtered or scored. That is not the same as unschedulable, which means a scheduling attempt was made and failed. The metric separates the two: scheduler_pending_pods carries a queue label and this Pod is counted under gated.
Play from step 2 -
The component that owns example.com/bar patches it out of the list. Entries come off in any order, and this one was second, so removing it says nothing about the other. Nothing else moves: STATUS still reads SchedulingGated and PodScheduled is still False, because one entry left in the list is enough to hold the Pod out.
Play from step 3 -
There is no way back. After creation the API accepts a removal and refuses an addition, so a component that lets its gate go cannot take it again, and a Pod created without gates can never be given one. Whatever wants to hold a Pod with a gate has to put it on at creation or lose the chance.
Play from step 4 -
The last entry goes the same way and the list is now empty. Emptying it is the whole trigger: there is no separate signal and this Pod waits on nothing else, so the moment spec.schedulingGates has no entries left it is ready to be considered for scheduling.
Play from step 5 -
The Pod joins the active queue, and the Scheduler can now make its first attempt at it. Only the metric moves, to queue active. STATUS and PodScheduled still read SchedulingGated, because the API server wrote that condition at creation and nothing rewrites it until the Scheduler finishes an attempt. What follows is the ordinary cycle: filter the Nodes, score, and bind.
Play from step 6