Introduction
The Kubernetes scheduler makes placement decisions based on what each pod asks for and what each node can provide. These challenges walk through the core scheduling concepts - from requests and limits, through eviction policy and quota enforcement, to explicit placement rules.
Each challenge builds on the previous one. By the end you will know not just how individual scheduling features work, but how they interact when you need full control over where a pod runs.
Resources (challenges 1-4): requests, QoS classes, priority and preemption, LimitRange and ResourceQuota.
Placement (challenges 5-8): pod affinity, nodeSelector and node affinity, topology spread, dedicated nodes with taints and tolerations.
Autoscaling (challenge 9): HPA - where requests and utilization meet.
Resource Requests
Every scheduling decision starts here. When you set requests.cpu and requests.memory on a container, the scheduler uses those values to find a node with enough available capacity. A pod with no requests can land anywhere - including a node that is already under pressure.
Quality of Service Classes
Requests and limits do more than inform the scheduler - they determine a pod's QoS class, which controls eviction order when a node runs low on memory. A pod with no requests or limits is the first to go. A pod with requests equal to limits is the last.
Priority and Preemption
When a cluster is full and a new pod cannot be scheduled, PriorityClass determines what happens next. A high-priority pod can evict lower-priority pods to claim their resources. preemptionPolicy: Never lets you set a priority without granting eviction rights - useful for jobs that should queue ahead of others without disrupting running workloads.
LimitRange and ResourceQuota
Setting requests and limits on every pod manually does not scale. LimitRange injects defaults into pods that omit them, and rejects any pod that exceeds a defined ceiling. ResourceQuota caps the total consumption across an entire namespace. Together they enforce resource discipline without relying on every developer to get it right.
Pod Affinity and Anti-Affinity
Resource requests tell the scheduler what a pod needs from a node. Affinity rules tell it what a pod needs from other pods. Co-locate a frontend with its cache. Keep two replicas off the same node. These rules express pod-to-pod relationships that no resource constraint can capture.
nodeSelector and Node Affinity
nodeSelector targets a node with a simple key-value match. Node affinity is its expressive replacement - same result, but with operators like In, NotIn, and Exists, and a preferred variant that falls back when no node matches. This challenge bridges directly into the next one: the taints and tolerations challenge uses required node affinity as half of the dedicated-node solution.
Topology Spread Constraints
Anti-affinity keeps two pods apart. Topology spread constraints distribute an entire deployment evenly across nodes or zones. The difference is intent: anti-affinity is a hard rule between specific pods, topology spread is a distribution policy across the whole replica set.
Taints, Tolerations and Node Affinity
Node affinity pulls the right pods toward a node. Taints push everything else away. Neither is enough on its own - a toleration lets a pod land on a tainted node, but does not force it there. Node affinity pulls a pod toward a node, but without a taint anything else can land there too. Dedicated nodes require both.
Horizontal Pod Autoscaler
HPA watches CPU utilization as a percentage of requests.cpu and adjusts the replica count automatically. The requests.cpu value the scheduler uses for placement is the same value HPA divides actual usage against. Without it, HPA has no baseline and cannot scale.