k8s-容忍Toleration和污点Taint

k8s-容忍Toleration和污点Taint
十八岁k8s-容忍Toleration和污点Taint
1.容忍和污点概念
在 Kubernetes 中,污点(Taints) 和 容忍(Tolerations) 是一对协同工作的机制,用于控制哪些 Pod 可以被调度到特定的 Node(节点)上。
核心概念
- 污点(Taint):附加在 Node 上的属性。它就像给节点打上了「排斥标记」,默认情况下会拒绝所有不能容忍该污点的 Pod 被调度上来。
- 容忍(Toleration):配置在 Pod 规范(
spec.tolerations)中的规则。它代表 Pod 拥有针对特定污点的「免疫力」,允许(但不强求)该 Pod 调度到带污点的节点。
污点的三要素与效果
一个 Taint 由 key=value:effect 构成,其中 effect 决定了具体的排斥行为:
| 效果(Effect) | 行为说明 |
|---|---|
NoSchedule |
强排斥:若 Pod 未容忍,绝不调度到该节点;已在运行的 Pod 不受影响。 |
PreferNoSchedule |
软排斥:尽量避免调度,但如果资源实在紧张,依然可能调度。 |
NoExecute |
驱逐排斥:若 Pod 未容忍,不仅不能调度,已经在节点上运行的 Pod 也会被立即驱逐(可配置 tolerationSeconds 延迟驱逐)。 |
核心作用
- 节点隔离:防止普通应用 Pod 侵占关键或特殊用途节点的资源。
- 避免故障蔓延:在节点出现异常(如网络不可达、磁盘耗尽)时,自动驱逐无法继续运行的业务 Pod。
- 精细化调度:与节点亲和性(Node Affinity)配合,实现节点与 Pod 的精准双向绑定。
典型应用场景
- 专有资源隔离(如 GPU / 高内存节点) 将昂贵的 GPU 节点打上
gpu=true:NoSchedule污点,只有配置了相应 toleration 的深度学习任务才能调度上来,防止普通的 Nginx 或 Web 服务挤占 GPU 节点 CPU/内存。 - Master / 控制平面节点保护 K8s 集群默认会给 Master 节点打上
node-role.kubernetes.io/control-plane:NoSchedule污点,确保只有 API Server、CoreDNS 等集群关键组件可以运行,业务容器不会干扰控制面。 - 基于节点状态的动态驱逐 当节点出现故障时,Node Controller 会自动给节点打上内置污点(如
node.kubernetes.io/unreachable:NoExecute或node.kubernetes.io/not-ready:NoExecute)。普通 Pod 会立即被驱逐并在健康节点重建;若应用需要容忍短暂网络抖动,可在 Toleration 中设置tolerationSeconds: 300延迟驱逐。 - 节点维护与排空(Drain) 节点升级维护前,添加
NoExecute污点可以平滑将现有业务驱逐到其他节点。
提示:污点是「排斥机制」(拒绝不需要的 Pod),若要让特定 Pod「必须」跑在指定节点上,需结合 Node Affinity(节点亲和性) 共同使用。
2.污点命令格式解析
在 Kubernetes 中,污点(Taints)主要通过 kubectl taint 命令进行管理。它的基本语法结构与 kubectl label 非常相似。
语法结构如下:
1 | kubectl taint nodes <节点名称> <key>=<value>:<effect> |
**<节点名称>**:目标 Node 的名称(可通过 kubectl get nodes 查看)。
**<key>**:污点的键名(支持带有域名前缀,如 [example.com/gpu](https://example.com/gpu))。
**<value>**:污点的值(可为空,空值时语法为 <key>:<effect>)。
**<effect>**:污点生效策略,仅支持三种:
NoSchedule:不容忍则不调度。PreferNoSchedule:尽量不调度。NoExecute:不容忍则驱逐并拒绝新调度。
例如:给GPU节点添加一个特殊资源的污点
1 | kubectl taint nodes k8s-node01 gpu=true:NoSchedule |
2.1添加一个污点
给节点添加污点,一个节点可以有多个污点,多个污点时,key可以重复,effect不可以重复
1 | 添加一个污点 |
1 | 添加一个同名不同影响度的污点: |
1 | 添加一个不包含 value 的污点 |
1 | 同时添加多个污点 |
1 | 同时为多个节点添加污点 |
1 | 同时添加所有节点(也可以基于 Label) |
2.2删除一个污点
删除污点(和label类似)
1 | 基于key删除,相同key的污点可以有多个,如果不精确指定会删除所有key是ssd的污点 |
1 | 基于key+Effect删除 |
1 | 基于完整格式删除 |
2.3修改污点
如果某个 key 和 effect 已经存在,修改其 value 需要加上 --overwrite 参数:
1 | kubectl taint nodes node-1 dedicated=high-memory:NoSchedule --overwrite |
2.4查看节点上的污点
1 | kubectl get nodes k8s-master01 -o go-template --template {{.spec.taints}} |
1 | kubectl describe nodes k8s-master01|grep Taints -A 10 |
3.常见内置污点
Kubernetes 会在节点出现特定条件或生命周期事件时,由控制器自动为节点打上内置污点。这些内置污点通常带有标准的前缀(如 node.kubernetes.io/)。自己在配置污点时不要使用内置污点的这些key
| 内置污点(Key) | 典型 Effect | 触发条件与作用 |
|---|---|---|
node-role.kubernetes.io/control-plane |
NoSchedule |
控制面节点(Master)专用污点,防止普通业务 Pod 调度到控制节点。 |
node.kubernetes.io/not-ready |
NoExecute |
节点处于非就绪状态(Ready: False),kubelet 心跳超时或未就绪时触发。 |
node.kubernetes.io/unreachable |
NoExecute |
控制平面无法与节点通信(NodeController 判定节点失联)。 |
node.kubernetes.io/unschedulable |
NoSchedule |
节点被设置为不可调度(执行 kubectl cordon 时自动打上)。 |
node.kubernetes.io/memory-pressure |
NoSchedule |
节点节点内存不足(达到驱逐阈值)。 |
node.kubernetes.io/disk-pressure |
NoSchedule |
节点根分区或容器运行时镜像分区磁盘空间不足。 |
node.kubernetes.io/pid-pressure |
NoSchedule |
节点上分配的进程 ID(PID)耗尽。 |
node.kubernetes.io/network-unavailable |
NoSchedule |
节点网络插件(CNI)尚未配置完成或网络不可达。 |
node.cloudprovider.kubernetes.io/uninitialized |
NoSchedule |
云厂商控制器(CCM)尚未初始化完成该节点时自动打上。 |
4.容忍配置解析
在 Kubernetes 中,容忍规则主要通过 key、operator、value 和 effect 的组合来决定匹配的严格程度。
4.1完全匹配(精确匹配)
要求 key、value 和 effect 必须与节点上的污点完全一致。
1 | tolerations: |
⚙️ 参数机制:
operator: "Equal":指示需要精确比对键和值。value: "frontend":指定具体要匹配的值。effect: "NoSchedule":限定只容忍NoSchedule类型的效果。
📌 适用场景:只有带有 tier=frontend:NoSchedule 污点的节点才会被容忍;如果节点上的污点值是 backend,或者效果是 NoExecute,则无法匹配。
假设三个节点的污点设置如下,Pod 能够成功容忍并调度到哪几个节点上:成功容忍并调度到节点3上
🖥️ 节点 1:的污点:tier=backend:NoSchedule
🖥️ 节点 2:的污点:tier=frontend:NoExecute
🖥️ 节点 3:的污点:tier=frontend:NoSchedule
4.2键名匹配(Key 存在即可)
只要节点存在指定的 key,无论其 value 是什么,都可以容忍。
1 | tolerations: |
⚙️ 参数机制:
operator: "Exists":只检查键名是否存在。value:必须留空。Exists模式下不能指定值。
📌 适用场景:只要节点打了 gpu 键的污点(例如 gpu=v100:NoSchedule 或 gpu=a100:NoSchedule),该 Pod 都能容忍并调度上去,effect参数也需要匹配。
假设三个节点的污点设置如下,Pod 能够成功容忍并调度到哪几个节点上:成功容忍并调度到节点1上
- 🖥️ 节点 1:
gpu=tesla:NoSchedule - 🖥️ 节点 2:
gpu=rtx4090:NoExecute - 🖥️ 节点 3:
storage=ssd:NoSchedule
4.3忽略 Effect 的匹配(不完全/宽泛匹配)
指定了 key(及可选的 value),但**省略了 effect**。
1 | tolerations: |
⚙️ 参数机制:
effect省略:系统默认匹配该键值下的所有 effect 类型(包括NoSchedule、PreferNoSchedule和NoExecute)。
📌 适用场景:节点只要满足 node-role=storage,不论其生效策略是禁止调度还是立即驱逐,Pod 都会全部容忍。
4.4容忍所有污点(通配所有)
无条件容忍节点上的任何污点。
1 | tolerations: |
⚙️ 参数机制:
key为空 且operator: "Exists":代表“只要有任何污点存在就匹配”。- 配合
effect省略,便构成了对所有key、所有value、所有effect的全盘容忍。
📌 适用场景:系统级守护进程(如某些必须运行在每一个节点上的 DaemonSet,例如 CNI 网络插件、监控 Agent)。
4.5容忍一段时间的匹配(驱逐缓冲)
主要用于应对节点突发故障或网络抖动,避免 Pod 被立刻驱逐。
1 | tolerations: |
⚙️ 参数机制:
effect: "NoExecute":tolerationSeconds只能在该效果下生效。tolerationSeconds: 300:节点出现unreachable污点后,Pod 不会被立即踢走,而是继续在节点上存活 300 秒(5 分钟)。
📌 适用场景:有状态服务或重建代价较高的应用。如果节点在 5 分钟内恢复网络,Pod 就不需要重建;若 5 分钟后仍未恢复,控制器才会将其驱逐并重新调度。
要触发这个倒数计时,通常不是在「建立 Pod 时节点就已经有污点」,而是在Pod 运行过程中,节点动态被打上了这个污点。
来看一个典型的生产环境场景:
📦 Pod 设定(完全匹配 + 缓冲 60 秒):
1
2
3
4
5
6tolerations:
- key: "maintenance"
operator: "Equal"
value: "true"
effect: "NoExecute"
tolerationSeconds: 60🔄 触发的完整时间线:
- 🟢 平时:节点健康,上面没有
maintenance=true:NoExecute这个污点。Pod 顺利调度并正常运行。 - 🛠️ 节点维护开始(T = 0 秒): 维护人员执行命令,给节点打上污点:
kubectl taint nodes k8s-node01 maintenance=true:NoExecute - 🔍 系统检查与计时启动:
- 节点上其他普通 Pod(没有容忍的)→ 立即被全部驱逐!
- 你的 Pod 检查规则:
key、value、effect完全匹配! - 系统发现你设定了
tolerationSeconds: 60,于是启动 60 秒倒数计时器。
- ⏳ 60 秒内: 你的 Pod 获得这 60 秒的安全时间,可以用来处理尚未完成的请求、储存日志或做优雅关机(Graceful Shutdown)。
- 🛑 满 60 秒(T = 60 秒): 如果此时节点上的维护污点还在,倒数结束,系统正式将你的 Pod 强制驱逐并在其他节点重建。
- 🟢 平时:节点健康,上面没有
5.实战-主节点禁止调度
在生产环境中,Kubernetes 的主节点除了部署系统组件外,不推荐再部署任何服务,此时可以通过添加污点来禁止调度,NoSchedule并不会影响以及部署的pod。
1 | kubectl taint node k8s-master01 k8s-master02 k8s-master03 node-role.kubernetes.io/control-plane:NoSchedule |
也可以添加NoExecute类型的污点,此时不容忍该污点的pod会被驱逐重建:
1 | kubectl taint node k8s-master01 k8s-master02 k8s-master03 node-role.kubernetes.io/control-plane:NoExecute |
6.实战-新节点禁止调度
当 Kubernetes 集群添加新节点时,通常情况下不会立即调度 Pod 到该节点,新添加的节点需要经过完整 的可用性测试之后才可以调度 Pod,此时也可以使用污点先临时禁止该节点的调度:
1 | kubectl taint node k8s-node04 new-node=true:NoSchedule |
同样的道理,比如在禁止调度之前已经有 Pod 部署在该节点,可以进行驱逐:
1 | kubectl taint node k8s-node04 new-node=true:NoExecute |
待新节点测试完毕后,在允许该节点可以进行调度,删除之前添加的污点:
1 | kubectl taint node k8s-node04 new-node- |
7.实战-节点维护流程
当 Kubernetes 的节点需要进行下线维护时,此时需要先把该节点的服务进行驱逐和重新调度。
此时需要根据实际情况判断是直接驱逐还是选择重新调度,比如某个 Pod 只有一个副本, 或者某个服务比较重要,就不能直接进行驱逐,而是需要先把节点关闭调度,然后在进行服务的 重新部署。
先把需要维护的节点添加一个污点,假设k8s-node03要维护:
1 | 先为k8s-node03添加污点,NoSchedule表示新pod如果没有容忍不在调度到node03上,但是node03上已有的不影响 |
假设redis-7b68666f59-skvm9比较重要,使用rollout restart触发更新
1 | kubectl rollout restart deployment -n project-prod redis |
再次查看该pod,已经部署到k8s-node02节点上了:
1 | kubectl get po -n project-prod -owide |
接下来如果没有重要服务,即可对该节点的pod进行驱逐:
1 | kubectl taint node k8s-node03 maintain:NoExecute |
驱逐后,即可按照预期对节点进行维护,维护完成后可以删除污点,恢复调度:
1 | kubectl taint node k8s-node03 maintain- |
除了自定义污点,也可以使用 kubectl 快捷指令将节点设置为维护状态:
1 | kubectl cordon k8s-node03 |
此时节点会被标记一个 SchedulingDisabled 状态,但是已经运行在该节点的 Pod 不受影响:
1 | [root@k8s-master01 ~]# kubectl cordon k8s-node03 |
然后再根据服务的重要性使用rollout restart 来滚动更新重要的服务,使其重新调度到其他节点,然后再使用快捷指令驱逐节点上其他的pod:
1 | kubectl drain k8s-node03 --ignore-daemonsets --delete-emptydir-data |
维护结束使用快捷指令恢复调度:
1 | kubectl uncordon k8s-node03 |
1 | [root@k8s-master01 ~]# kubectl uncordon k8s-node03 |
| 命令 | 作用 | 对现有Pod的影响 | 典型场景 |
|---|---|---|---|
cordon |
仅禁止新Pod调度 | 无影响,继续运行 | 维护前准备、观察节点负载自然下降 |
drain |
禁止调度 + 驱逐现有Pod | 会被优雅终止并迁移 | 正式下线节点、系统升级重启 |
uncordon |
解除禁止调度 | - | 维护完成,恢复节点使用 |
8.实战-节点特殊资源保留
当 Kubernetes 中存储特殊节点时,应该尽量保持不需要特殊资源的 Pod 不要调度到这些节点 上,此时可以通过污点进行控制。
比如包含了 GPU 的节点不能被任意调度:
1 | kubectl taint node k8s-node03 gpu=true:NoSchedule |
具有其它特殊资源,尽量不要调度:
1 | kubectl taint node k8s-node02 ssd=true:PreferNoSchedule |
9.实战-调度到具有污点的节点
在生产环境中,经常根据实际情况给节点打上污点,比如特殊资源节点不能随意调度、主节 点不能随意调度,但是需要特殊资源的服务还是需要调度到该节点,一些监控和收集的服务还是 需要调度到主节点,此时需要给这些服务添加合适的容忍才能部署到这些节点。
比如上述添加的 GPU 污点:
1 | kubectl taint node k8s-node03 gpu=true:NoSchedule |
如果某个服务需要 GPU 资源,就需要添加容忍才能部署至该节点。此时可以添加如下的容 忍配置至 Pod 上:
1 | tolerations: |
完整配置如下:
1 | # 需要注意的是节点有污点,pod有容忍并不代表pod一定会调度到该节点上 |
1 | [root@k8s-master01 21-taints]# kubectl create -f my-app.yaml |
接下来给节点添加一个标签,并配置节点选择器,让pod调度到k8s-node03:
1 | 为 k8s-node03 添加标签 |
资源完整配置如下:
1 | cat my-app.yaml |
创建资源并查看pod所在的节点:
1 | [root@k8s-master01 21-taints]# kubectl replace -f my-app.yaml |
10.实战-专用节点隔离
一个 Kubernetes 集群,很常见会有一些专用的节点,比如 ingress、gateway、storage 或者 多租户环境等。这些节点通常不建议和其他服务交叉使用,所以需要利用污点和容忍将这些节点 隔离起来。
比如选择一批节点作为 ingress 入口的节点:
1 | kubectl label node k8s-node02 ingress=true |
添加一个污点,不让其他服务部署
1 | kubectl taint node k8s-node02 ingress=true:NoSchedule |
更改 Ingress 的部署资源,添加容忍和节点选择器:
1 | kubectl edit -n ingress-nginx daemonset.apps/ingress-nginx-controller |
11.实战-节点宕机快速恢复服务
当 Kubernetes 集群中有节点故障时,Kubernetes 会自动恢复故障节点上的服务,但是默认 情况下,节点故障时五分钟才会重新调度服务,此时可以利用污点的 tolerationSeconds 快速恢 复服务。
1 | apiVersion: apps/v1 |








