Skip to content

第 2 章:Taints 污点详解

2.1 污点的数据结构

污点定义在 Node 对象的 spec.taints 中,每个污点由三部分组成:

key=value:effect
yaml
apiVersion: v1
kind: Node
metadata:
  name: node1
spec:
  taints:
  - key: "dedicated"        # 键:1-63 字符,可带 DNS 前缀如 example.com/dedicated
    value: "gpu"            # 值:可选,0-63 字符
    effect: "NoSchedule"    # 效果:NoSchedule / PreferNoSchedule / NoExecute
  • key 必填,命名规则与 label 相同。
  • value 可省略kubectl taint nodes node1 key1:NoSchedule 是合法的(此时容忍端通常用 Exists 运算符匹配)。
  • 同一个节点可以有多个污点,key+effect 组合唯一。

2.2 kubectl taint 命令大全

添加污点

bash
# 完整形式:key=value:effect
kubectl taint nodes node1 dedicated=gpu:NoSchedule

# 不带 value
kubectl taint nodes node1 maintenance:NoSchedule

# 给所有节点打污点(谨慎!)
kubectl taint nodes --all env=prod:NoSchedule

# 按 label 选择器批量打污点
kubectl taint nodes -l hardware=gpu dedicated=gpu:NoSchedule

# 覆盖已存在的同 key+effect 污点
kubectl taint nodes node1 dedicated=gpu:NoSchedule --overwrite

查看污点

bash
# 方式一:describe(最直观)
kubectl describe node node1 | grep -A5 Taints

# 方式二:jsonpath(适合脚本)
kubectl get node node1 -o jsonpath='{.spec.taints}'

# 查看集群所有节点的污点
kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints

删除污点

bash
# 删除指定 key+effect 的污点(注意末尾的减号)
kubectl taint nodes node1 dedicated=gpu:NoSchedule-

# 删除该 key 的所有 effect 污点
kubectl taint nodes node1 dedicated:NoSchedule-   # 只删 NoSchedule 效果
kubectl taint nodes node1 dedicated-              # 删除 key 为 dedicated 的所有污点

# 删除所有节点上的污点
kubectl taint nodes --all dedicated-

⚠️ 删除语法是新手最易错点:减号 - 紧跟在 effect(或 key)之后,中间不能有空格

修改污点

污点没有"原地修改"命令,用 --overwrite 重新打,或先删后加:

bash
kubectl taint nodes node1 dedicated=gpu:PreferNoSchedule --overwrite

2.3 三种 Effect 深入对比

2.3.1 NoSchedule —— 硬调度约束

  • 新 Pod 没有对应容忍 → 绝不调度到该节点。
  • 已在节点上运行的 Pod 不受影响,继续运行。
bash
kubectl taint nodes node1 dedicated=backend:NoSchedule

典型场景:Master 节点保护(K8s 默认给 control-plane 打 node-role.kubernetes.io/control-plane:NoSchedule)、专用节点池。

2.3.2 PreferNoSchedule —— 软调度约束

  • 调度器尽量避免把没有容忍的 Pod 调度上来,但实在没地方去时仍会调度上来
  • 这是"柔性"版本,用于不希望硬隔离、只做倾向性引导的场景。
bash
kubectl taint nodes node1 env=staging:PreferNoSchedule

常见误区:以为 PreferNoSchedule 能完全挡住 Pod。它挡不住,集群资源紧张时 Pod 照样会上来。

2.3.3 NoExecute —— 调度约束 + 驱逐

最强力的效果,两层作用:

  1. 调度层面:等同于 NoSchedule,没容忍的新 Pod 不能上来。
  2. 驱逐层面已经在该节点运行、且没有对应容忍的 Pod 会被驱逐(Evict)
bash
kubectl taint nodes node1 maintenance=true:NoExecute
# 结果:node1 上没有容忍此污点的 Pod 会被立即驱逐,重新调度到其他节点

配合 Pod 容忍里的 tolerationSeconds 字段,还可以实现"延迟驱逐"(见第 3、4 章)。

2.4 驱逐过程详解(NoExecute)

管理员执行:kubectl taint nodes node1 maintenance:NoExecute


┌──────────────────┐
│  node1 上的 Pod   │
│  逐个检查容忍      │
└──────────────────┘
   │            │
   │ 无容忍      │ 有容忍
   ▼            ▼
 立即驱逐    ┌─────────────────────┐
 (Evicted)  │ tolerationSeconds?  │
            │  未设置 → 永久容忍    │
            │  = 300 → 300秒后驱逐 │
            └─────────────────────┘

被驱逐的 Pod 状态变为 Failed,原因 Evicted;如果由 Deployment 管理,控制器会在其他节点重建新副本。

2.5 多污点叠加:AND 语义

节点上的多个污点之间是"与(AND)"关系:Pod 必须容忍节点上的每一个污点,才能调度上来。

bash
kubectl taint nodes node1 dedicated=gpu:NoSchedule
kubectl taint nodes node1 team=ai:NoSchedule

Pod 需要同时容忍 dedicated=gpu:NoSchedule team=ai:NoSchedule 才能调度到 node1。

注意:Pod 的容忍可以比节点的污点(多余的容忍无害),但不能

2.6 污点的命名规范建议

前缀/键用途
node-role.kubernetes.io/control-plane控制面节点(内置)
node.kubernetes.io/*K8s 内置污点(not-ready、unreachable 等,见第 4 章)
自定义如 dedicatedteamhardware业务自定义,建议加公司域名前缀如 example.com/dedicated 避免冲突

本章小结

  • 污点格式 key=value:effect,value 可省略,effect 三选一。
  • kubectl taint 增删查:删除用结尾减号 -
  • NoSchedule 硬拒、PreferNoSchedule 软拒、NoExecute 硬拒 + 驱逐。
  • 多污点是 AND 关系,Pod 必须全部容忍。

动手练习

  1. 给一个节点打 NoSchedule 污点,部署一个 3 副本的 Deployment(不带容忍),观察 Pod 的分布和 Pending 情况。
  2. 把污点改为 NoExecute,观察该节点上原有 Pod 被驱逐的过程(kubectl get pods -o wide -w)。
  3. 练习删除污点,验证 Pod 恢复正常调度。