Kubernetes Scheduling & Resources
How the scheduler places Pods, resource requests and limits, QoS classes and eviction, health probes, and affinity and topology-spread controls.
9 questions
JuniorTheoryVery commonWhat is the difference between a Pod's resource requests and limits?
What is the difference between a Pod's resource requests and limits?
requests are what the scheduler reserves — a Pod lands only where a node's allocatable still fits the summed requests. limits cap runtime use: past a CPU limit the container is throttled, past a memory limit it is OOMKilled. A Pod with no requests can land on any node and starve its neighbours.
Common mistakes
- ✗Swapping the roles — thinking
limits, notrequests, drive scheduling - ✗Expecting a CPU limit to OOMKill rather than throttle the container
- ✗Omitting
requests, letting a Pod schedule anywhere and starve others
Follow-up questions
- →What QoS class does a Pod with requests equal to limits get?
- →Why can over-committing
limitswhile under-settingrequestscause node OOM?
JuniorTheoryCommonWhat does the Kubernetes scheduler do, and what decides which node a Pod lands on?
What does the Kubernetes scheduler do, and what decides which node a Pod lands on?
The scheduler assigns each unscheduled Pod to a node in two phases. Filtering keeps only nodes that fit the Pod's requests and its taint, nodeSelector and affinity; scoring then ranks the survivors and the best one wins. If no node passes filtering, the Pod stays Pending.
Common mistakes
- ✗Thinking the scheduler runs the Pod rather than only choosing its node
- ✗Believing filtering checks
limitsinstead ofrequests - ✗Assuming a Pod is always placed, forgetting it can stay
Pending
Follow-up questions
- →How are DaemonSet Pods placed differently from scheduler-driven Pods?
- →Which node conditions make filtering reject an otherwise-empty node?
MiddleDebuggingCommonA Pod is stuck Pending — read the scheduler events and give the diagnosis.
A Pod is stuck Pending — read the scheduler events and give the diagnosis.
No node fits, for two reasons. The 2 general nodes fail on Insufficient cpu (the Pod asks 4 CPU). The 3 GPU nodes carry an untolerated taint dedicated=gpu; preemption won't help — it frees no CPU and lifts no taint. Fix: shrink the request or add nodes; for GPU nodes add a toleration and nodeAffinity.
Common mistakes
- ✗Blaming only CPU and ignoring the untolerated-taint half of the message
- ✗Expecting preemption to place a Pod that no node can physically fit
- ✗Thinking a toleration alone makes the Pod prefer the GPU nodes
Follow-up questions
- →What single change would let this Pod schedule on a general node?
- →Why does
Preemption not helpfulappear for the GPU nodes here?
MiddleTheoryCommonHow are the Guaranteed, Burstable and BestEffort QoS classes derived, and how do they affect eviction?
How are the Guaranteed, Burstable and BestEffort QoS classes derived, and how do they affect eviction?
QoS comes from requests and limits: Guaranteed = requests equal limits everywhere, Burstable = at least one request set but unequal, BestEffort = none set. Under node memory pressure the kubelet evicts BestEffort first, then over-request Burstable, and Guaranteed last.
Common mistakes
- ✗Thinking QoS comes from priority rather than from requests and limits
- ✗Reversing eviction order — evicting Guaranteed before BestEffort
- ✗Assuming
BestEffortis safe because it sets no limit to exceed
Follow-up questions
- →Why can a
BurstablePod staying under its requests survive pressure? - →How does QoS-based eviction differ from priority-based preemption?
MiddleTheoryCommonDo a taint and a toleration attract a Pod to a node? How does that differ from nodeAffinity?
Do a taint and a toleration attract a Pod to a node? How does that differ from nodeAffinity?
No — taints REPEL. A taint keeps Pods off a node unless the Pod carries a matching toleration, and the toleration only REMOVES the bar — it never pulls the Pod onto the node. nodeAffinity and nodeSelector are what ATTRACT. So landing a Pod on a dedicated tainted node needs BOTH a toleration and affinity.
Common mistakes
- ✗Believing a toleration attracts a Pod instead of only permitting it
- ✗Skipping nodeAffinity, expecting a toleration alone to pin the Pod
- ✗Treating taints and affinity as the same mechanism, not orthogonal ones
Follow-up questions
- →How would you dedicate a GPU node pool to only GPU workloads?
- →What does
podAntiAffinityadd that a node taint cannot express?
MiddleTheoryOccasionalWhat do topologySpreadConstraints do, and how do maxSkew and topologyKey control the spread?
What do topologySpreadConstraints do, and how do maxSkew and topologyKey control the spread?
They spread matching Pods evenly across topology domains named by topologyKey — zones or nodes. maxSkew caps how uneven the per-domain Pod counts may get; whenUnsatisfiable sets whether a Pod that breaks the skew stays Pending (DoNotSchedule) or is placed anyway (ScheduleAnyway).
Common mistakes
- ✗Reading
maxSkewas a per-node Pod cap rather than an allowed imbalance - ✗Assuming even spread is automatic without a spread constraint
- ✗Swapping
DoNotScheduleandScheduleAnywaysemantics
Follow-up questions
- →How does this
topologyKeydiffer from apodAntiAffinitytopologyKey? - →When would you choose
ScheduleAnywayoverDoNotSchedule?
SeniorTheoryOccasionalHow do PriorityClasses and preemption work, and how do PodDisruptionBudgets bound the evictions?
How do PriorityClasses and preemption work, and how do PodDisruptionBudgets bound the evictions?
A PriorityClass gives a Pod a priority value. When a high-priority Pod can't schedule, the scheduler preempts — evicting lower-priority Pods to free their requests so it fits. A PodDisruptionBudget bounds only VOLUNTARY disruption (drain, rollout), not preemption or node failure.
Common mistakes
- ✗Believing a PDB blocks preemption rather than only voluntary disruption
- ✗Thinking preemption picks victims by QoS instead of by priority
- ✗Reading
PriorityClassas a resource reservation, not a ranking
Follow-up questions
- →Can preemption cascade, and how does a graceful termination period apply?
- →What happens when honouring a PDB would block a required node drain?
SeniorCodeOccasionalComplete a Deployment so its Pods run only on the dedicated GPU node pool.
Complete a Deployment so its Pods run only on the dedicated GPU node pool.
Add BOTH: a toleration matching the taint so GPU nodes stop repelling the Pod, and a required nodeAffinity on accelerator=gpu so it is attracted only there. The toleration alone merely permits GPU nodes; without affinity the Pod could still land on any untainted node. Together they pin it to the pool.
Common mistakes
- ✗Adding only a toleration and expecting it to attract the Pod
- ✗Adding only nodeAffinity and hitting the untolerated
NoScheduletaint - ✗Believing affinity overrides a taint, so no toleration is needed
Follow-up questions
- →How would you keep general Pods OFF the GPU nodes at the same time?
- →When is
preferredDuringSchedulingaffinity the better choice here?
SeniorDesignOccasionalYou run a 6-replica sharded cache (stateful) plus a latency-sensitive API that calls it heavily, on one cluster spanning 3 availability zones. Requirements: the cache replicas must be spread so losing any one zone takes down at most a third of them; the API Pods should sit on the same nodes as — or very close to — the cache to keep call latency low; and a rolling update must never take more than one cache replica down at a time. Design the scheduling policy — which of nodeAffinity, podAffinity, podAntiAffinity, topologySpreadConstraints and PodDisruptionBudgets you use for each requirement and how you set the key parameters. Explain the trade-off between spreading for availability and co-locating for latency.
You run a 6-replica sharded cache (stateful) plus a latency-sensitive API that calls it heavily, on one cluster spanning 3 availability zones. Requirements: the cache replicas must be spread so losing any one zone takes down at most a third of them; the API Pods should sit on the same nodes as — or very close to — the cache to keep call latency low; and a rolling update must never take more than one cache replica down at a time. Design the scheduling policy — which of nodeAffinity, podAffinity, podAntiAffinity, topologySpreadConstraints and PodDisruptionBudgets you use for each requirement and how you set the key parameters. Explain the trade-off between spreading for availability and co-locating for latency.
Spread the cache with a zone-key topologySpreadConstraint (maxSkew: 1, DoNotSchedule) so a zone holds at most a third. Co-locate the API via podAffinity on the cache label, topologyKey hostname or zone. Bound the rollout with a PDB maxUnavailable: 1. Trade-off: spreading aids availability but adds a hop.
Common mistakes
- ✗Using
podAntiAffinityto co-locate, which actually pushes Pods apart - ✗Trusting the scheduler to spread across zones without a constraint
- ✗Expecting tolerations to co-locate the API onto the cache nodes
Follow-up questions
- →How would
whenUnsatisfiable: ScheduleAnywaychange the availability guarantee? - →What breaks if a whole zone is lost mid-rollout under this policy?