Kubernetes nodeSelector and Taints: Pin a Workload to a Node Pool

nodeSelector attracts a pod to a node pool; a toleration lets it past the pool's taint. You need both to pin a workload to dedicated hardware and keep everything else off. Here's how the pattern works and what the manifest looks like.

Kubernetes Engineerkuberneteskubectlnodeselector

Why you need both nodeSelector and a toleration

Taints and node selectors solve opposite halves of the same problem.

A taint on a node repels pods - dedicated=batch:NoSchedule means "nothing schedules here unless it explicitly opts in." It keeps general workloads off your batch pool. Without a taint, other pods will happily land on your dedicated hardware.

A nodeSelector attracts a pod to nodes that carry a matching label - workload: batch tells the scheduler "only place me on nodes with this label." Without the selector, your batch pod could land on any untainted node.

Together: the taint keeps the crowd out, the selector steers your pod in.

Label and taint the node pool

Before the Deployment can use them, the nodes need to be labeled and tainted:

kubectl label node <node-name> workload=batch
kubectl taint node <node-name> dedicated=batch:NoSchedule

In managed clusters (GKE, EKS, AKS) this is done through the node pool configuration - the same logic, just applied at provisioning time.

The Deployment manifest

Add nodeSelector and tolerations under spec.template.spec:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: batch
spec:
  replicas: 1
  selector:
    matchLabels:
      app: batch
  template:
    metadata:
      labels:
        app: batch
    spec:
      nodeSelector:
        workload: batch          # must match the node label
      tolerations:
      - key: dedicated
        operator: Equal
        value: batch
        effect: NoSchedule       # must match the taint effect
      containers:
      - name: batch
        image: busybox:1.36
        command: ["sleep", "86400"]

Apply it and confirm the fields landed in the live spec:

kubectl apply -f deployment.yaml
kubectl get deploy batch -o yaml | grep -A4 'nodeSelector\|tolerations'

Toleration fields explained

Field What it matches
key The taint key (dedicated)
operator Equal (exact match) or Exists (any value)
value The taint value (batch)
effect NoSchedule, PreferNoSchedule, or NoExecute

A toleration with operator: Exists and no key is a wildcard - it tolerates every taint on the node. Useful for DaemonSets, but too broad for workload pinning.

NoSchedule vs NoExecute

NoSchedule prevents new pods from landing but leaves existing pods running. NoExecute evicts pods that are already on the node and lack a matching toleration (add tolerationSeconds to delay eviction). Use NoSchedule for node pools; reserve NoExecute for drain-style operations.

Want to try it hands-on? HeyDevJob gives you this exact setup in a live cloud workspace in your browser - edit it, run it, and see it work. Free, nothing to install.

Try it in a workspace →

What you'll practice

FAQ

What is the difference between nodeSelector and taints in Kubernetes?

nodeSelector steers a pod toward nodes that have a specific label - it's a pod-side rule. Taints repel pods from a node unless the pod carries a matching toleration - it's a node-side rule. You need both to pin a workload to a dedicated pool and keep everything else off.

How do I pin a pod to a specific node pool in Kubernetes?

Label the nodes in the pool (e.g. workload=batch), taint them (e.g. dedicated=batch:NoSchedule), then add a matching nodeSelector and toleration to the Deployment's pod spec. The scheduler only places the pod on nodes that satisfy both.

What does NoSchedule mean on a Kubernetes taint?

NoSchedule prevents new pods without a matching toleration from being scheduled onto that node. Pods already running on the node are not evicted. Use NoExecute instead if you want to evict existing pods that don't tolerate the taint.

Keep learning

Fix a Kubernetes CrashLoopBackOffKubernetes projectHeal a Kubernetes Service With No EndpointsKubernetes projectFix a Kubernetes ImagePullBackOffKubernetes projectKubernetes roadmapStep by step to hiredKubernetes interview questionsSTAR answersAll Kubernetes projectsProjects hub

Learn it by doing. Open this in a live cloud workspace, make the change yourself, and keep a record of the work you can share.

Open the workspace →