
September 10, 2026
13 min read
By Kokil Thapa | Last reviewed: September 2026
Taints and Tolerations in Kubernetes are the scheduler's gatekeepers. They decide which pods may run on which nodes. Node affinity nudges workloads toward preferred hardware. Taints push everyone else away unless a pod explicitly opts in. If you run mixed workloads on shared clusters—GPU nodes, spot instances, or dedicated database pools—you need this mechanism. The concepts pair with the Kubernetes scheduler and node architecture. This guide walks through effects, kubectl commands, YAML patterns, and the failures you will see in production.
What are taints and tolerations in Kubernetes?
A taint is a property of a node. It tells the scheduler: reject pods that do not tolerate this label. A toleration is a property of a pod. It says: I am allowed on nodes with this taint. Neither feature assigns a pod to a node by itself. They only remove nodes from consideration or allow entry past a gate.
Think of a taint as a "keep out" sign on a door. A toleration is the key card. Without the card, the scheduler skips that node entirely. With it, the node becomes eligible—subject to other rules like resource requests, affinity, and topology spread.
Every taint has three parts:
- Key — identifies the taint (for example
dedicatedorgpu) - Value — optional qualifier (for example
ml-training) - Effect — what happens to non-tolerating pods
Tolerations mirror the same key-value pair and add an optional effect and tolerationSeconds for temporary admission. The scheduler evaluates them during the filtering phase described in Kubernetes control plane and node architecture.
The three taint effects
Kubernetes supports three effect values. Each behaves differently for existing and new pods.
| Effect | New pods without toleration | Existing pods without toleration |
|---|---|---|
NoSchedule | Not scheduled on this node | Keep running |
PreferNoSchedule | Scheduler tries to avoid the node | Keep running |
NoExecute | Not scheduled on this node | Evicted after tolerationSeconds (or immediately if zero) |
NoSchedule is the default choice for dedicated hardware. NoExecute suits maintenance windows and node drains. PreferNoSchedule is a soft hint—the scheduler may still place a pod if no better option exists.
Official reference: the Kubernetes taint and toleration documentation defines matching rules. An empty key with operator: Exists tolerates every taint with that effect.
How do you add taints to a Kubernetes node?
You apply taints with kubectl taint or by editing the node object directly. Most teams use kubectl during operations and encode taints in node pools for cloud-managed clusters.
Using kubectl taint
# Taint a node — dedicated GPU pool
kubectl taint nodes gpu-node-1 gpu=true:NoSchedule
# Taint with a specific value
kubectl taint nodes db-node-1 dedicated=postgres:NoExecute
# Remove a taint (note trailing dash)
kubectl taint nodes gpu-node-1 gpu:NoSchedule-
# List node taints
kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints Cloud providers add taints automatically in common scenarios. EKS marks nodes with node.kubernetes.io/unreachable:NoExecute when a node stops responding. GKE taints preemptible nodes. AKS applies similar markers. These system taints protect cluster stability during failures.
On bare-metal or self-managed clusters—similar to setups covered in K3s for edge Kubernetes—you set taints manually when provisioning node roles.
Built-in taints you will encounter
Kubernetes and cloud integrations ship several well-known taints:
node.kubernetes.io/not-ready:NoExecute— node is not readynode.kubernetes.io/unreachable:NoExecute— node lost contact with control planenode.kubernetes.io/disk-pressure:NoSchedule— low disk spacenode.kubernetes.io/memory-pressure:NoSchedule— low memorynode.kubernetes.io/pid-pressure:NoSchedule— too many processesnode.kubernetes.io/unschedulable:NoSchedule— node cordoned for drain
When you run kubectl drain, Kubernetes cordons the node and adds the unschedulable taint. Pods without toleration for that taint are evicted. This ties directly to worker node lifecycle management.
How do tolerations work in a pod specification?
Tolerations live under spec.tolerations in the pod template. Deployments, StatefulSets, DaemonSets, and Jobs all use the same field. A toleration must match a taint's key, value, and effect—or use wildcards.
Exact match toleration
apiVersion: apps/v1
kind: Deployment
metadata:
name: ml-training
spec:
replicas: 2
selector:
matchLabels:
app: ml-training
template:
metadata:
labels:
app: ml-training
spec:
tolerations:
- key: "gpu"
operator: "Equal"
value: "true"
effect: "NoSchedule"
containers:
- name: trainer
image: pytorch/pytorch:2.4.0-cuda12.4
resources:
limits:
nvidia.com/gpu: 1 This pod schedules onto nodes tainted with gpu=true:NoSchedule. It also schedules onto untainted nodes unless node affinity restricts placement further. Toleration alone does not force a pod onto a tainted node—it only removes the block.
Exists operator — tolerate any value
tolerations:
- key: "dedicated"
operator: "Exists"
effect: "NoSchedule" This tolerates any taint whose key is dedicated, regardless of value. Use it when one team owns all dedicated nodes under a single key namespace.
Tolerate all taints (use carefully)
tolerations:
- operator: "Exists" An empty key with Exists matches every taint. DaemonSets for log collectors and node monitors often use this pattern. They must run on every node, including tainted ones. See GPU scheduling on Kubernetes for a dedicated-hardware example that combines tolerations with resource limits.
tolerationSeconds for temporary admission
When a node gains a NoExecute taint, pods with a matching toleration can stay for a grace period:
tolerations:
- key: "node.kubernetes.io/unreachable"
operator: "Exists"
effect: "NoExecute"
tolerationSeconds: 300 After 300 seconds, the pod is evicted even though it tolerates the taint. This gives short-lived workloads time to finish without immediate termination during brief network blips.
How do taints and tolerations differ from node affinity?
Teams often confuse taints with node affinity. They solve opposite sides of the same problem. Taints repel pods from nodes. Affinity attracts pods toward nodes. You frequently use both together.
| Feature | Taints / Tolerations | Node Affinity |
|---|---|---|
| Applied to | Taint on node; toleration on pod | Affinity rules on pod only |
| Default behaviour | All pods blocked unless tolerating | All nodes eligible unless restricted |
| Primary purpose | Exclusive node pools, isolation | Prefer or require specific nodes |
| Eviction support | Yes, via NoExecute | No direct eviction |
| Typical pattern | Taint GPU nodes; only GPU pods tolerate | Require zone=us-east-1a label |
A practical pattern for a production Laravel API on Kubernetes—covered in Kubernetes for Laravel getting started—looks like this:
- Taint worker nodes reserved for the API with
workload=api:NoSchedule. - Add a matching toleration to the API Deployment pod template.
- Add required node affinity for
workload=apilabel so pods land only on those nodes. - Leave general workloads unable to schedule on API nodes.
Taints enforce the boundary. Affinity pins placement inside the boundary. Without affinity, a tolerating pod could still land on any eligible node—including untainted shared nodes.
Resource requests and limits remain independent. A pod can tolerate a GPU taint but still fail scheduling if the node lacks free GPU capacity. Review resource limits and requests alongside taint design.
What are common use cases for taints and tolerations?
Most production clusters use taints for isolation, cost control, and operational safety. These patterns appear across managed and self-hosted environments.
Dedicated node pools
Reserve expensive instances for workloads that need them. Taint GPU or high-memory nodes. Only pods with tolerations—and usually affinity—schedule there. General Deployments never accidentally consume GPU capacity.
Spot and preemptible instances
Cloud spot nodes receive taints like cloud.google.com/gke-preemptible. Batch Jobs and fault-tolerant workers add tolerations. Stateful services stay away unless you explicitly accept interruption risk. Pair this with pod disruption budgets from horizontal pod autoscaling planning.
Control plane isolation
Many installers taint control plane nodes with node-role.kubernetes.io/control-plane:NoSchedule. Only system components like CoreDNS and the CNI tolerate this taint. Application pods cannot land on masters—a baseline security practice aligned with Kubernetes RBAC hardening.
Node maintenance and upgrades
During upgrades, operators cordon and drain nodes. The unschedulable taint blocks new pods. NoExecute taints evict running pods after their grace period. Plan tolerationSeconds on stateful workloads carefully. Too short causes unnecessary failovers. Too long delays maintenance.
Multi-tenant soft isolation
Platform teams taint namespaces' dedicated nodes per tenant. Each tenant's Helm chart includes tolerations in values.yaml. This is simpler than separate clusters for small and mid-size teams. For enterprise isolation requirements, see enterprise application development patterns that map tenancy to infrastructure.
On booking platforms I've maintained—similar in complexity to trek booking systems on Laravel—staging and production node pools often carry distinct taints. CI preview environments tolerate staging taints only. Production Deployments never carry staging tolerations. A misconfigured toleration is cheaper to catch at schedule time than in a live incident.
How do you troubleshoot taints and tolerations scheduling issues?
The most common symptom is a pod stuck in Pending with a scheduler message about taints. Less obvious cases involve pods landing on wrong nodes because tolerations are too broad.
Read scheduler events
kubectl describe pod my-app-7f8b9c-xyz | grep -A5 Events
# Typical output:
# Warning FailedScheduling ... 0/4 nodes available: 1 node(s) had taint
# {gpu: true}, that the pod didn't tolerate, 3 node(s) didn't match
# Pod's node affinity/selector. The message tells you exactly which taint blocked placement. Cross-check node taints:
kubectl describe node gpu-node-1 | grep -i taint Compare against the pod spec:
kubectl get pod my-app-7f8b9c-xyz -o jsonpath='{.spec.tolerations}' | jq A regex tester helps validate label selectors and taint key patterns when you generate manifests from templates.
Common mistakes
- Effect mismatch — pod tolerates
NoSchedulebut node hasNoExecute - Value mismatch — taint value is
gpubut toleration expectstrue - Missing toleration on init containers' pod — tolerations apply to the whole pod spec, not per container, so this is usually a template sync issue
- Over-broad Exists toleration — pod schedules onto maintenance-tainted nodes unintentionally
- Taint removed but affinity still required — pod pending for affinity, not taints; read the full event
For pods that crash after scheduling, taints are not the cause. Follow CrashLoopBackOff debugging instead. For performance issues after placement, see Kubernetes performance tuning.
Validate before production
Run a dry-run scheduling check in staging:
# Create a test pod with your tolerations
kubectl run taint-test --image=nginx:1.27 --overrides='
{
"spec": {
"tolerations": [{"key":"gpu","operator":"Equal","value":"true","effect":"NoSchedule"}]
}
}' --dry-run=server -o yaml Some clusters support --dry-run=server for admission validation. For full scheduling simulation, use tools like kubectl apply on a staging cluster with identical node taints. Document taint keys in your internal runbook. Treat them like API contracts between platform and application teams.
Managed cluster upgrades often preserve node-pool taints automatically. Self-managed clusters using Kubespray or similar—see deploy Kubernetes with Kubespray—require taints in your node group definitions so rebuilds stay consistent.
For ongoing cluster operations, Linux system administration and support and maintenance services cover the node-level work that keeps taint policies stable across upgrades.
Key Takeaways
- Taints repel pods from nodes; tolerations let specific pods through—neither forces placement by itself.
- Use
NoSchedulefor dedicated pools,NoExecutefor maintenance, andPreferNoSchedulefor soft spot-instance preference. - Apply taints with
kubectl taint nodes NAME key=value:Effect; remove them with a trailing dash on the effect. - Combine tolerations with required node affinity when you need exclusive placement, not just admission.
- Read
FailedSchedulingevents for exact taint mismatches when pods stay Pending. - Avoid wildcard
Existstolerations on application pods unless you truly need to run everywhere.
People Also Ask
Can a pod run on a node without a toleration if the node has no taints?
Yes. Untainted nodes accept all pods that pass other scheduling checks. Taints are opt-out markers on nodes; tolerations are opt-in keys on pods. No taint means no taint gate.
Do taints affect DaemonSets?
DaemonSets schedule one pod per eligible node by default. They do not tolerate taints unless you add tolerations to the DaemonSet spec. System DaemonSets like CNI plugins include tolerations for control plane and not-ready taints so they run everywhere.
What happens if I taint a node that already has running pods?
With NoSchedule or PreferNoSchedule, existing pods keep running. Only new pods without tolerations are blocked. With NoExecute, existing pods without a matching toleration are evicted immediately or after tolerationSeconds.
Are taints the same as node labels?
No. Labels are arbitrary metadata used for selection and affinity. Taints actively affect scheduling and eviction. You often put matching labels and taints on the same node pool—labels for affinity, taints for exclusion—but they are separate fields on the Node object.
Build cleaner Kubernetes scheduling on your next cluster
Taints and Tolerations in Kubernetes give you precise control over which workloads share which hardware. Start with dedicated pools for expensive or sensitive nodes. Add tolerations only to pods that belong there. Layer node affinity when you need guaranteed placement. Read scheduler events when pods stick in Pending—they name the taint that blocked them.
If you are designing cluster architecture for a Laravel app, a multi-tenant SaaS platform, or a mixed batch-and-API environment, taints belong in your first infrastructure diagram—not as an afterthought during a production incident. For hands-on help with cluster design, node pools, and deployment pipelines, contact us or explore the portfolio of production platforms already running on disciplined infrastructure. More background on scheduling lives in the Kubernetes blog archive and the about page.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

