Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Taints and Tolerations in Kubernetes

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 dedicated or gpu)
  • 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.

Kubernetes Scheduling with TaintsPodwith tolerationsSchedulerfilter phaseEligible Nodestaint matchedNode A (tainted)gpu=true:NoScheduleNode B (tainted)dedicated=db:NoScheduleNode C (clean)no taintsblockedallowedPod without matching toleration cannot schedule on tainted nodesToleration = explicit opt-in only
How taints and tolerations in Kubernetes filter nodes during scheduler placement

The three taint effects

Kubernetes supports three effect values. Each behaves differently for existing and new pods.

EffectNew pods without tolerationExisting pods without toleration
NoScheduleNot scheduled on this nodeKeep running
PreferNoScheduleScheduler tries to avoid the nodeKeep running
NoExecuteNot scheduled on this nodeEvicted 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 ready
  • node.kubernetes.io/unreachable:NoExecute — node lost contact with control plane
  • node.kubernetes.io/disk-pressure:NoSchedule — low disk space
  • node.kubernetes.io/memory-pressure:NoSchedule — low memory
  • node.kubernetes.io/pid-pressure:NoSchedule — too many processes
  • node.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.

Taint Effect ComparisonNoScheduleHard blockNew pods onlyExisting stayPreferNoScheduleSoft avoidMay place anywayExisting stayNoExecuteHard blockEvicts runningAfter grace periodDecision guideDedicated poolNoSchedulePrefer spotPreferNoScheduleMaintenanceNoExecute
Choosing the right taint effect for taints and tolerations in Kubernetes node pools

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.

FeatureTaints / TolerationsNode Affinity
Applied toTaint on node; toleration on podAffinity rules on pod only
Default behaviourAll pods blocked unless toleratingAll nodes eligible unless restricted
Primary purposeExclusive node pools, isolationPrefer or require specific nodes
Eviction supportYes, via NoExecuteNo direct eviction
Typical patternTaint GPU nodes; only GPU pods tolerateRequire 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:

  1. Taint worker nodes reserved for the API with workload=api:NoSchedule.
  2. Add a matching toleration to the API Deployment pod template.
  3. Add required node affinity for workload=api label so pods land only on those nodes.
  4. 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.

Dedicated Node Pool PatternGPU Node PoolTaint: gpu=true:NoScheduleLabel: hardware=gpuBlocks general podsAllows ML pods onlyGeneral Node PoolNo taintsRuns web, cache, queueCost-efficient sharedNo GPU overheadML Pod SpecToleration: gpuAffinity: hardware=gpuForces GPU placementWeb Pod SpecNo GPU tolerationNo GPU affinitySchedules general pool
Combining taints, tolerations, and affinity for isolated Kubernetes node pools

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 NoSchedule but node has NoExecute
  • Value mismatch — taint value is gpu but toleration expects true
  • 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.

Pending Pod TroubleshootingPod status: Pendingkubectl describe pod — read EventsMentions taint? Compare key, value, effectFix tolerationAdd to pod specRedeployOther causeCheck affinityCheck resources
Diagnostic flow for taints and tolerations in Kubernetes pending pod errors

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 NoSchedule for dedicated pools, NoExecute for maintenance, and PreferNoSchedule for 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 FailedScheduling events for exact taint mismatches when pods stay Pending.
  • Avoid wildcard Exists tolerations 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

A taint is a node property that blocks pods without a matching toleration. A toleration on the pod opts in. Neither assigns placement; they only gate which nodes the scheduler may consider.

NoSchedule blocks new pods without a matching toleration while existing pods keep running. PreferNoSchedule is a soft hint the scheduler tries to honor, but it may still place a pod if no better node exists. NoExecute blocks new pods and evicts existing ones without toleration after tolerationSeconds, or immediately when that value is zero. NoSchedule suits dedicated hardware; NoExecute suits maintenance and drains.

Apply taints with kubectl taint nodes NAME key=value:Effect during operations, or edit the node object directly. Cloud-managed clusters often encode taints in node pool definitions so rebuilds stay consistent. Remove a taint by repeating the command with a trailing dash on the effect, such as gpu:NoSchedule-. List current taints with kubectl get nodes using a custom columns output for the TAINTS field.

Tolerations live under spec.tolerations in Deployments, StatefulSets, DaemonSets, and Jobs. Each entry matches a taint key, optional value, and effect using operator Equal for exact matches, or Exists to match any value for a given key. A toleration removes the scheduling block but does not force the pod onto that node. Other rules such as resource requests, affinity, and topology spread still apply.

Taints on nodes repel pods unless the pod carries a matching toleration. Node affinity rules on the pod attract workloads toward preferred or required nodes. In production you often use both: taints enforce an exclusive boundary on dedicated pools, while required node affinity pins permitted pods inside that boundary. Without affinity, a tolerating pod can still schedule on any eligible untainted node that passes other checks.

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.

Yes. DaemonSets 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 on every node.

With NoSchedule or PreferNoSchedule, existing pods without toleration keep running; only new pods are blocked or discouraged from scheduling there. With NoExecute, existing pods without a matching toleration are evicted immediately or after their tolerationSeconds grace period expires. That is why NoExecute fits maintenance windows and node drains, while NoSchedule fits reserving expensive dedicated hardware.

operator Exists matches a taint key regardless of its value, which helps when one team owns all dedicated nodes under a single key namespace. An empty key with Exists and a specific effect tolerates every taint carrying that effect. A fully empty Exists entry matches all taints, a pattern DaemonSets for log collectors and node monitors use to run everywhere. Application pods should avoid wildcard Exists unless they truly must schedule onto every tainted node.

tolerationSeconds gives pods with a matching NoExecute toleration a grace period before eviction when a node gains that taint. A common pattern tolerates node.kubernetes.io/unreachable with tolerationSeconds 300 so short-lived workloads survive brief network blips. After the period expires, the pod is evicted even though it tolerates the taint. Plan this value carefully on stateful workloads: too short causes unnecessary failovers; too long delays maintenance.

Reserve GPU or high-memory nodes for workloads that need them, run batch Jobs on spot or preemptible instances via cloud-specific taints, keep application pods off control-plane nodes, cordon and drain nodes during upgrades, and give each tenant dedicated nodes in multi-tenant clusters via Helm chart tolerations. On platforms I have maintained, staging and production pools often carry distinct taints so CI preview environments never schedule onto production hardware.

Run kubectl describe pod and read FailedScheduling events; they name the exact taint the pod did not tolerate and how many nodes were excluded. Compare kubectl describe node taint output against the pod spec tolerations field. Frequent causes are effect mismatch, value mismatch such as gpu versus true, missing tolerations in the pod template, or an over-broad Exists toleration sending pods onto maintenance-tainted nodes. If the event mentions affinity instead, fix node affinity rather than tolerations.

NoSchedule is the default choice for dedicated hardware including GPU pools. It stops general Deployments from accidentally consuming GPU capacity while pods with matching tolerations remain eligible. Toleration alone is not enough for exclusive placement: combine the taint with required node affinity on the pool label so GPU jobs land only on those nodes, not on untainted shared nodes. Also confirm resource limits such as nvidia.com/gpu match actual node capacity.

Kubernetes applies node.kubernetes.io/not-ready and node.kubernetes.io/unreachable with NoExecute, plus disk-pressure, memory-pressure, and pid-pressure with NoSchedule. During kubectl drain, the unschedulable taint blocks new pods on a cordoned node. Cloud providers add their own markers: EKS sets unreachable on failed nodes, GKE taints preemptible instances, and AKS applies similar failure taints. Expect these during outages and plan tolerationSeconds on stateful workloads accordingly.

No. Taints and tolerations only repel pods from nodes or allow admission past a gate; they do not assign placement by themselves. Combine tolerations with required node affinity when you need exclusive placement inside a dedicated pool. Resource requests and limits remain independent, so a pod can tolerate a GPU taint but stay Pending if no node has free GPU capacity. Validate toleration and affinity together in staging before production rollout.

Share this article

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.

Quick Contact Options
Choose how you want to connect me: