污点与容忍
本教程共 65 篇 · 第 41 篇 · 更新于 2026-08-14 · 约 15 分钟阅读
本节目标:理解污点(Taint)和容忍度(Toleration)是怎么配合的,记住三种效果的区别,会用 kubectl 给节点打污点,并能在 Pod 上写容忍度;最后知道几个真实场景。
前面讲亲和性时,思路是”Pod 主动挑节点”。污点和容忍反过来了:它让节点主动说”我不想接某些 Pod”。一个节点一旦带上污点,普通 Pod 就调度不上去,除非 Pod 自己声明”我能容忍这个污点”。
这套机制专门用来把 Pod 挡在或赶出某些节点,而不是像亲和性那样把 Pod 拉过去。
41-1 一个生活化的比喻
把节点想成几间会议室。污点就像贴在门上的告示:“本会议室仅限项目组 A”。普通同事(Pod)看到告示就绕开了。但项目组 A 的成员手里拿着对应的通行证(容忍度),保安才放他们进去。
注意,污点管的是”能不能进去”,不是”必须进去”。即便你有通行证,也只是”可以被放进这间会议室”,不代表你一定被安排到这里。最终坐哪还取决于调度器对其他因素的判断。
Note污点(Taint)加在节点上,容忍度(Toleration)写在 Pod 上。两者配合,节点才能决定是否接收某个 Pod。
41-2 给节点打污点
给节点添加污点用 kubectl taint 命令。一个污点由三部分组成:键(key)、值(value)、效果(effect)。
kubectl taint nodes node1 key1=value1:NoSchedule
这条命令给 node1 加了一个污点:键是 key1,值是 value1,效果是 NoSchedule。意思很直接——只要 Pod 没有匹配的容忍度,就别想调度到 node1 上。
想摘掉这个污点,在末尾加个减号就行:
kubectl taint nodes node1 key1=value1:NoSchedule-
键和值你可以随意起名,但建议用域名风格,比如 dedicated=groupA、special=true,这样不容易和别人的污点撞车。
41-3 三种效果
污点的 effect 字段有三个取值,差别很大,这是本节的重点。
NoSchedule 是”硬性拒绝”。只要节点上有未被容忍的 NoSchedule 污点,新 Pod 就绝不会被调度上来。但已经在节点上运行的 Pod 不受影响,不会被赶走。
PreferNoSchedule 是”软性拒绝”。控制平面会尽量不把不能容忍的 Pod 放上来,但不保证。负载紧张、别无选择时,Pod 仍可能被调度过去。你可以把它理解成”能避开就避开”。
NoExecute 最狠,它既拦新 Pod,也赶旧 Pod。节点一旦被加上未被容忍的 NoExecute 污点,节点上跑着的、又无法容忍这个污点的 Pod 会被立刻驱逐。
Warning
NoExecute会驱逐已经在节点上运行的 Pod。生产环境给线上节点加NoExecute污点前,务必确认关键 Pod 都写好了容忍度,否则可能瞬间被大量驱逐。
41-4 在 Pod 上写容忍度
容忍度写在 Pod 规约的 tolerations 字段里。针对上面那条 key1=value1:NoSchedule 污点,下面两种写法都能匹配:
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoSchedule"
tolerations:
- key: "key1"
operator: "Exists"
effect: "NoSchedule"
第一种用 Equal,要求键、值、效果三者全对上。第二种用 Exists,只要求键和效果匹配,值无所谓。operator 的默认值是 Equal,所以你不写 operator 时,等于在用精确匹配。
一个容忍度”匹配”一个污点,要满足:键相同、效果相同,并且要么 operator 是 Exists(不写 value),要么 operator 是 Equal 且值相等。
Tip不确定值、只想按污点”类型”放行的场景,用
Exists更省事。想精确控制某类污点才放行,用Equal。
还有两个特殊写法:把 key 留空且 operator 为 Exists,能匹配所有键和值(但效果仍要一致);把 effect 留空,能匹配该键下的所有效果。
41-5 多个污点和多个容忍度
一个节点可以挂多个污点,一个 Pod 也能写多个容忍度。Kubernetes 的处理逻辑像个筛子:先列出节点上所有污点,再逐一划掉 Pod 能容忍的那些。剩下的、没被划掉的污点,才真正起作用。
- 只要剩下一个
NoSchedule没被划掉,Pod 就调度不上来。 - 没有剩下的
NoSchedule、但剩下一个PreferNoSchedule,调度器就尽量避开。 - 只要剩下一个
NoExecute没被划掉,已经运行的 Pod 会被驱逐,新 Pod 也调度不上来。
举个具体例子。给节点加三个污点:
kubectl taint nodes node1 key1=value1:NoSchedule
kubectl taint nodes node1 key1=value1:NoExecute
kubectl taint nodes node1 key2=value2:NoSchedule
Pod 只写了两个对 key1 的容忍度,没有容忍 key2=value2:NoSchedule。那么第三个污点没被划掉,结果是 Pod 调度不上去。但如果 Pod 在这之前就已经跑在 node1 上,它还能继续跑——因为只有第三个污点是它唯一不能容忍的,而 NoExecute 那两个它都容忍了。
41-6 tolerationSeconds:给个缓冲期
NoExecute 的容忍度还能带一个 tolerationSeconds 字段,表示”就算容忍,最多也只待这么久”。
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoExecute"
tolerationSeconds: 3600
假设这个 Pod 正在运行,此时节点被加上匹配的 NoExecute 污点。Pod 不会立刻被赶走,而是再陪节点待 3600 秒(一小时),然后才被驱逐。如果这一小时内污点被摘掉了,Pod 就安全留下。
这在网络分区时很有用:你希望一个状态很重的 Pod 多撑一会儿,等网络恢复,避免被误驱逐。
NoteKubernetes 会自动给每个 Pod 加上对
node.kubernetes.io/not-ready和node.kubernetes.io/unreachable的容忍度,且tolerationSeconds=300。也就是说节点刚出问题时,Pod 默认还能在节点上赖 5 分钟。
41-7 内置污点与基于污点的驱逐
节点出问题时,节点控制器会自动给节点加污点。常见的有这些:
node.kubernetes.io/not-ready:节点没就绪,对应 Ready 为 False。node.kubernetes.io/unreachable:节点连不上,对应 Ready 为 Unknown。node.kubernetes.io/memory-pressure:节点内存有压力。node.kubernetes.io/disk-pressure:节点磁盘有压力。node.kubernetes.io/pid-pressure:节点进程数有压力。node.kubernetes.io/network-unavailable:节点网络不可用。node.kubernetes.io/unschedulable:节点被标记为不可调度。
其中 not-ready 和 unreachable 默认带 NoExecute 效果。节点恢复正常后,对应的污点会被移除,Pod 也就不必再担心被驱逐。
自 Kubernetes 1.29 起,这层”基于污点的驱逐”已经从节点控制器里拆出来,成为一个独立组件 taint-eviction-controller。如果确实不需要,可以在 kube-controller-manager 里加 --controllers=-taint-eviction-controller 把它关掉。
调度器做决定时看的是污点,而不是节点状况本身。这样设计的好处是:节点状况不会直接搅乱调度逻辑,统一通过污点这一层来表达”别来”。
TipDaemonSet 的 Pod 自带针对
unreachable和not-ready的NoExecute容忍度,且没有tolerationSeconds。所以节点出问题时,DaemonSet 的 Pod 不会被驱逐,日志采集、监控这类守护进程才能一直在线。
41-8 数值比较运算符
除了 Equal 和 Exists,还可以用 Gt(大于)和 Lt(小于)做数值匹配,前提是污点值和容忍度值都是整数。这个能力由特性门控 TaintTolerationComparisonOperators 控制(v1.35 引入,目前是 alpha 特性、默认关闭),需要在 apiserver、kubelet 等组件上显式开启才可用。
比如按 SLA 等级给节点打污点:
kubectl taint nodes node1 servicelevel.organization.example/agreed-service-level=950:NoSchedule
Pod 写容忍”SLA 大于 900 的节点”:
tolerations:
- key: "servicelevel.organization.example/agreed-service-level"
operator: "Gt"
value: "900"
effect: "NoSchedule"
因为 950 > 900,这条容忍度命中。注意:两边的值都得是合法的 64 位整数,带前导零(如 "0550")会被拒。污点值本身在节点注册时不做校验,所以若节点上的污点值是非数字,用了数值运算符的 Pod 就匹配不上。
41-9 典型使用场景
专用节点:把一批机器只给某个团队用。给这些节点打 dedicated=groupName:NoSchedule,再给该团队的 Pod 加对应容忍度。DaemonSet 之外的 Pod 进不来。要是想”只允许进这批专用节点”,还得额外给节点打同名标签,并配合节点亲和性强制 Pod 只能落在带该标签的节点。
特殊硬件节点:少数节点有 GPU 这类特殊设备。给它们打 special=true:NoSchedule,用了 GPU 的 Pod 才加容忍度,把普通 Pod 挡在外面,给后来的 GPU 任务留位置。更省心的做法是配合扩展资源和 ExtendedResourceToleration 准入控制器——你申请了扩展资源,准入控制器会自动帮你补上容忍度。
基于污点的驱逐:这正是上一节说的节点故障时自动保护。节点失联或not-ready,Pod 按内置容忍度撑一会儿,必要时被温和地请走,再被调度到健康节点。
41-10 几个易混点
污点和容忍是”放行”而非”吸引”。有容忍度不代表一定被调度到该节点,只是”允许”而已。真正想把 Pod 定向放过去,要靠节点亲和性。
手动指定 .spec.nodeName 会绕过调度器。即使目标节点有 NoSchedule 污点,Pod 也会被强行绑上去。这时若节点还有 NoExecute 污点,kubelet 会把它驱逐,除非它有对应容忍度。
污点和亲和性经常搭配使用:污点负责”挡”,亲和性负责”拉”,二者合起来才能既保证专用,又保证只用专用节点。
Note本章只讲污点与容忍的核心机制。关于节点亲和性怎么和污点配合实现”专用且只用专用”,可回看第 39、40 章的内容。