Kubernetes Manual Scheduling
Techniques to bypass or constrain the Kubernetes scheduler, pinning Pods to specific nodes. Manual scheduling is essential for debugging, node-local workloads, and the CKA exam’s “Workloads & Scheduling” domain. Synthesized from CKA Day 13 — Static Pods, Manual Scheduling, Labels, and Selectors.
What Is Manual Scheduling?
By default, Kubernetes uses the kube-scheduler to assign newly created Pods to nodes. The scheduler evaluates resource availability, taints, tolerations, affinity/anti-affinity rules, and data locality to pick the “best” node. Manual scheduling overrides this process, giving you direct control over node placement.
Key Insight: Manual scheduling is not a production anti-pattern — it is a deliberate tool. GPU workloads, licensing-bound software, zone-specific storage, and compliance requirements often mandate exact node placement. However, overuse leads to cluster imbalance and scheduling fragility. Source: CKA Day 13
Technique 1: nodeName (Direct Assignment)
The simplest and most forceful method. Setting nodeName in the Pod spec bypasses the scheduler entirely. The kubelet on the named node immediately attempts to run the Pod.
apiVersion: v1
kind: Pod
metadata:
name: pinned-pod
spec:
nodeName: worker-1 # Direct assignment — no scheduler evaluation
containers:
- name: nginx
image: nginxCharacteristics:
- No scheduler involvement: The Pod does not appear in the scheduler’s queue.
- No validation: If
worker-1is down, out of CPU/memory, or tainted, the Pod remains stuck inPendingwith no events explaining why. This is a common troubleshooting trap. - Use case: Emergency debugging, testing node-specific behavior, or when the scheduler is unavailable.
# Check why a nodeName-assigned Pod is stuck
kubectl describe pod pinned-pod
# Look for: 0/1 nodes are available: 1 node(s) had taint ...
# But because the scheduler skipped it, the message may be minimal.Technique 2: nodeSelector (Label-Based Filtering)
The recommended approach for simple manual scheduling. You label a node, then the Pod spec includes a nodeSelector that matches the label. The scheduler is still involved, but it only considers nodes that satisfy the selector.
# Label a node
kubectl label node worker-1 disk=ssd
kubectl label node worker-1 gpu=trueapiVersion: v1
kind: Pod
metadata:
name: fast-storage-pod
spec:
nodeSelector:
disk: ssd
containers:
- name: app
image: postgresCharacteristics:
- Scheduler validates: If no node matches, the Pod stays
Pendingwith a clear event:0/3 nodes are available: 3 node(s) didn't match Pod's node affinity/selector. - Multiple selectors: All key-value pairs must match on the same node (AND logic).
- Use case: SSD storage, GPU availability, OS type, zone placement.
Technique 3: Node Affinity (Advanced Constraint)
Node affinity is the advanced, expressive successor to nodeSelector. It supports “preferred” (soft) vs “required” (hard) constraints and set-based matching. See the dedicated deep-dive page for full YAML anatomy, operator reference, troubleshooting matrix, and the production pattern combining taints + affinity + tolerations.
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disk
operator: In
values:
- ssd
- nvme| Operator | Behavior |
|---|---|
In | Key has one of the listed values |
NotIn | Key does not have any of the listed values |
Exists | Key exists (regardless of value) |
DoesNotExist | Key does not exist |
Gt | Key value > specified integer |
Lt | Key value < specified integer |
Key Distinction: Both
requiredandpreferredtypes include the suffixIgnoredDuringExecution, meaning changes to node labels after scheduling do not evict existing Pods. This is fundamentally different fromNoExecutetaints. Source: CKA Day 15
Note: Node affinity is more verbose than
nodeSelectorbut offers soft constraints (preferredDuringSchedulingIgnoredDuringExecution) that allow the scheduler to place the Pod elsewhere if the ideal node is unavailable. This is the production-grade choice for node preference.
Technique 4: Taints and Tolerations (Negative Scheduling)
Taints are the inverse of node selectors: they repel Pods from nodes. A taint is a property on a node that says “do not schedule here unless you tolerate this condition.” This section provides a concise overview; see the dedicated page for a deep dive with full YAML anatomy, built-in taint catalog, and troubleshooting matrix.
# Taint a node
kubectl taint node worker-1 maintenance=true:NoSchedulespec:
tolerations:
- key: maintenance
operator: Equal
value: "true"
effect: NoSchedule| Effect | Behavior |
|---|---|
NoSchedule | New Pods without a toleration are not scheduled |
PreferNoSchedule | Soft avoidance — scheduler tries to avoid but will place if no alternative |
NoExecute | Evicts existing Pods without a toleration |
Common taints:
node-role.kubernetes.io/control-plane:NoSchedule— prevents user workloads on control plane nodesnode.kubernetes.io/not-ready:NoSchedule— automatically applied by the node controller
CKA Tip: To run a Pod on a control plane node, you must add a toleration for the control-plane taint. This is how
kube-proxyand some monitoring DaemonSets run on master nodes. Source: CKA Day 13 & Source: CKA Day 14
Comparative Summary
| Method | Scheduler Involved | Validation | Flexibility | Production Use |
|---|---|---|---|---|
nodeName | ❌ No | ❌ None | Minimal | Debugging only |
nodeSelector | ✅ Yes | ✅ Clear events | Low (exact match) | Simple constraints |
nodeAffinity | ✅ Yes | ✅ Clear events | High (soft/hard) | Complex constraints |
taints + tolerations | ✅ Yes | ✅ Clear events | Medium | Node isolation, maintenance |
Essential Commands
# List nodes with their labels
kubectl get nodes --show-labels
# Label a node
kubectl label node worker-1 disk=ssd
# Remove a label
kubectl label node worker-1 disk-
# Taint a node
kubectl taint node worker-1 gpu=true:NoSchedule
# Remove a taint
kubectl taint node worker-1 gpu=true:NoSchedule-
# Check which Pods are on a node
kubectl get pods --all-namespaces -o wide | grep worker-1
# Schedule a Pod with nodeName (imperative)
kubectl run debug --image=busybox --overrides='{"spec":{"nodeName":"worker-1"}}' --restart=NeverCKA Exam Relevance
- Workloads & Scheduling (~15%): Expect tasks to place a Pod on a specific node using
nodeName,nodeSelector, or tolerations. - Troubleshooting (~30%): A Pod stuck in
Pendingmay have anodeSelectorthat matches no nodes, or a missing toleration for a tainted node. - Speed Patterns:
kubectl run nginx --image=nginx --restart=Never --overrides='{"spec":{"nodeName":"worker-1"}}' kubectl label node worker-1 disk=ssd kubectl taint node worker-1 gpu=true:NoSchedule
Related Pages
- Kubernetes Architecture — kube-scheduler and kubelet roles
- Kubernetes Static Pods — node-level Pod management without the scheduler
- Kubernetes Labels and Selectors — the metadata system used by nodeSelector
- Kubernetes Taints and Tolerations — deep-dive on negative scheduling: effects, built-in taints, and troubleshooting
- Kubernetes Node Affinity — deep-dive on advanced positive scheduling: operators, soft/hard constraints, and the taints+affinity production pattern
- Kubernetes DaemonSet — uses tolerations to run on control plane nodes
- Pod Fundamentals — the object being scheduled
- Deployment, ReplicaSet & Replication Controller — controllers that respect scheduling constraints
- Kubernetes Namespaces — scoping does not affect scheduling
- CKA Certification — exam domains
- CKA Study Roadmap — Day 13–15 in the 40-day plan
- Tech Tutorials with Piyush — course source
Tags: kubernetes scheduling manual-scheduling node-selector node-affinity taints tolerations cka devops kube-scheduler