摘要:梳理 NoSchedule、PreferNoSchedule 与 NoExecute 的区别,掌握污点与容忍的匹配规则、容忍时间,以及与节点亲和性的配合。
本节学习 Kubernetes 节点调度中非常重要的一组机制:污点(Taints)与容忍度(Tolerations)。
- NodeSelector:根据节点标签选择节点。
- Node Affinity:根据节点标签进行灵活调度。
- Pod Affinity:让 Pod 靠近指定 Pod。
- Pod Anti-Affinity:让 Pod 远离指定 Pod。
- Topology Spread:控制 Pod 在不同拓扑域中的分布。
这些机制主要解决的是:
Pod 应该被调度到哪里?
而 Taints 与 Tolerations 主要解决:
哪些 Pod 可以进入某个节点?
这是两种不同的调度思路。
一、什么是 Taints 与 Tolerations?
1. Taints:节点污点
Taint(污点)是设置在 Node 上的一种调度限制。
它的作用是:
阻止不具备相应容忍条件的 Pod 被调度到该节点。
例如:
有一个专门用于数据库的节点:
Node-1:普通业务节点Node-2:普通业务节点Node-3:数据库专用节点我们希望:
- Node-1、Node-2 可以运行普通业务。
- Node-3 只运行数据库业务。
- 普通 Web Pod 不允许进入 Node-3。
可以给 Node-3 添加污点:
kubectl taint nodes Node-3 dedicated=database:NoSchedule此时:
flowchart TB
N0["Node-3"]
N1["dedicated=database:NoSchedule"]
N2["普通 Pod 无法调度进入"]
N0 --> N1
N1 --> N2
2. Tolerations:容忍度
Toleration(容忍度)是设置在 Pod 上的一种配置。
它表示:
Pod 能够容忍具有指定污点的节点。
例如:
数据库 Pod 配置:
tolerations: - key: dedicated operator: Equal value: database effect: NoSchedule这样数据库 Pod 就能够容忍:
dedicated=database:NoSchedule从而允许进入 Node-3。
注意:
容忍污点不等于一定会调度到该节点。
它只代表 Pod 不会因为这个污点而被排斥。仍然需要满足节点资源、亲和性等其他调度条件。
3. Taints 与 Tolerations 的关系
flowchart TB
subgraph G0["没有容忍度的普通 Pod"]
direction TB
N0["Web Pod<br/>无法容忍污点"]
end
subgraph G1["具有容忍度的数据库 Pod"]
direction TB
N1["Database Pod<br/>能够容忍污点"]
end
N2["Node-3<br/>dedicated=database:NoSchedule<br/>拒绝不匹配的 Pod<br/>允许通过污点检查"]
N0 --x|"拒绝不匹配的 Pod"| N2
N1 -->|"允许通过污点检查"| N2
记忆:
- Taint 设置在 Node 上。
- Toleration 设置在 Pod 上。
- Taint 是排斥条件。
- Toleration 是容忍条件。
二、Taint 的组成结构
Taint 由三个部分组成:
key=value:effect例如:
dedicated=database:NoSchedule三个部分分别是:
| 部分 | 示例 | 含义 |
|---|---|---|
| key | dedicated | 污点键 |
| value | database | 污点值 |
| effect | NoSchedule | 污点效果 |
其中 effect 非常重要。
Kubernetes 有三种主要污点效果:
- NoSchedule
- PreferNoSchedule
- NoExecute
三、Taint Effect:NoSchedule、PreferNoSchedule 与 NoExecute
1. NoSchedule:禁止调度
kubectl taint nodes worker-1 \ dedicated=database:NoSchedule含义:
没有对应容忍度的 Pod,不允许被调度到该节点。
例如:
flowchart TB
N0["Node-1"]
N1["Web Pod:没有容忍度"]
N2["DB Pod:有对应容忍度"]
N3["拒绝调度"]
N4["允许通过污点检查"]
N0 --> N1
N0 --> N2
N1 --> N3
N2 --> N4
注意:
NoSchedule 主要影响新 Pod 的调度。
如果某个 Pod 在添加污点之前已经运行在节点上,它不会仅仅因为添加了 NoSchedule 就自动被驱逐。
这是非常重要的区别。
2. PreferNoSchedule:尽量避免调度
kubectl taint nodes worker-1 \ dedicated=database:PreferNoSchedule含义:
Scheduler 尽量避免将不具备对应容忍度的 Pod 调度到该节点。
但是:
如果没有其他合适节点,仍然可能调度到这个节点。
它属于软性限制。
例如:
Node-1:PreferNoSchedule 污点Node-2:CPU 不足Node-3:CPU 不足如果 Node-1 是唯一可用节点,Pod 仍可能被调度到 Node-1。
3. NoExecute:禁止调度并驱逐
kubectl taint nodes worker-1 \ dedicated=database:NoExecute这是三种效果中限制最强的一种。
它有两个作用:
- 阻止不容忍该污点的新 Pod 被调度到节点。
- 驱逐已经运行在该节点、但不容忍该污点的 Pod。
例如:
flowchart TB
N0["Node-1"]
N1["Web Pod:没有容忍度"]
N2["DB Pod:有容忍度"]
N3["驱逐"]
N4["保留"]
N0 --> N1
N0 --> N2
N1 --> N3
N2 --> N4
注意:
NoExecute 不仅影响后续调度,还会影响已有 Pod。
4. 三种 Effect 对比
| Effect | 新 Pod | 已运行 Pod |
|---|---|---|
| NoSchedule | 不允许不匹配的 Pod 调度 | 不主动驱逐 |
| PreferNoSchedule | 尽量避免调度 | 不主动驱逐 |
| NoExecute | 不允许不匹配的 Pod 调度 | 驱逐不匹配的 Pod |
CKA 高频考点
记忆口诀:
- NoSchedule:不让进。
- PreferNoSchedule:尽量不让进。
- NoExecute:不让进,还要清出去。
四、Tolerations 配置详解
接下来学习如何让 Pod 容忍节点污点。
1. Equal:精确匹配
假设节点存在污点:
dedicated=database:NoSchedulePod 配置:
apiVersion: v1kind: Pod
metadata: name: mysql
spec: tolerations: - key: dedicated operator: Equal value: database effect: NoSchedule
containers: - name: mysql image: mysql:8.0解释:
| 参数 | 含义 |
|---|---|
| key | 匹配污点的键 |
| operator | Equal |
| value | 匹配污点的值 |
| effect | 匹配污点效果 |
只有污点的 key、value、effect 都符合规则时,才会被容忍。
2. Exists:只要求键存在
如果不关心污点的 value,只要 key 和 effect 匹配即可,可以使用 Exists。
例如:
tolerations: - key: dedicated operator: Exists effect: NoSchedule可以容忍:
dedicated=database:NoSchedulededicated=redis:NoSchedulededicated=storage:NoSchedule但是不能容忍:
gpu=nvidia:NoSchedule因为 key 不同。
3. Exists 与 Equal 对比
| 对比 | Equal | Exists |
|---|---|---|
| 匹配 key | 是 | 是 |
| 匹配 value | 是 | 否 |
| 匹配 effect | 指定时需要匹配 | 指定时需要匹配 |
| 灵活程度 | 精确 | 更宽泛 |
4. 空 key 的 Exists
还有一个特殊用法:
tolerations: - operator: Exists effect: NoSchedule这里没有指定 key。
表示:
容忍所有 key 的 NoSchedule 污点。
但不会自动容忍其他 effect,例如 NoExecute。
如果同时省略 key 和 effect:
tolerations: - operator: Exists则可以容忍所有污点。
生产环境需要谨慎使用,因为它会让 Pod 失去很多节点污点提供的隔离保护。
五、tolerationSeconds:容忍时间
这是 NoExecute 中非常重要的参数。
假设:
某个节点发生网络故障,Kubernetes 给节点添加了:
node.kubernetes.io/not-ready:NoExecute如果 Pod 没有容忍这个污点,就会被驱逐。
但是,有时候我们不希望 Pod 立即被驱逐。
例如:
节点只是短暂网络波动,我们希望等待 60 秒,观察节点能否恢复。
这时可以使用:
tolerations: - key: node.kubernetes.io/not-ready operator: Exists effect: NoExecute tolerationSeconds: 60含义:
Pod 可以容忍这个 NoExecute 污点 60 秒。
如果 60 秒后污点仍然存在,Pod 就会被驱逐。
1. 三种情况
| 配置 | 行为 |
|---|---|
| 不配置 tolerationSeconds | 对匹配的 NoExecute 污点无限期容忍 |
tolerationSeconds: 60 | 容忍 60 秒 |
tolerationSeconds: 0 | 不等待,立即进入驱逐流程 |
注意:
tolerationSeconds 只适用于 NoExecute,不能用于 NoSchedule 或 PreferNoSchedule。
2. 完整示例
apiVersion: v1kind: Pod
metadata: name: nginx
spec: tolerations: - key: dedicated operator: Equal value: database effect: NoExecute tolerationSeconds: 60
containers: - name: nginx image: nginx:1.27如果节点存在:
dedicated=database:NoExecute那么:
- 新创建的 Pod 可以容忍该污点。
- Pod 已经运行时,可以继续运行 60 秒。
- 60 秒后,如果污点仍存在,就会进入驱逐流程。
这里需要注意:容忍时间是从 Pod 开始容忍该污点时计算的,不是从 Pod 创建时计算的。
六、一个节点存在多个 Taint 怎么办?
生产环境中,一个节点可以同时存在多个污点。
例如:
worker-1
dedicated=database:NoSchedulegpu=nvidia:NoSchedulemaintenance=true:NoExecute现在创建一个 Pod:
tolerations: - key: dedicated operator: Equal value: database effect: NoSchedule这个 Pod 只能容忍:
dedicated=database:NoSchedule但不能容忍:
gpu=nvidia:NoSchedulemaintenance=true:NoExecute因此仍然无法正常调度到该节点。
核心规则:一个 Pod 必须容忍节点上所有会排斥它的污点,才能通过污点检查。
例如:
tolerations: - key: dedicated operator: Equal value: database effect: NoSchedule
- key: gpu operator: Equal value: nvidia effect: NoSchedule
- key: maintenance operator: Equal value: "true" effect: NoExecute这样才同时容忍上述三个污点。
注意:容忍全部污点也不代表 Pod 一定能调度到节点,还需要通过其他调度检查。
七、Taints 与 Node Affinity 如何配合?
这是生产环境非常重要的知识。
假设我们有一个数据库专用节点:
worker-1我们的需求是:
- 普通 Pod 不允许进入。
- 数据库 Pod 可以进入。
- 数据库 Pod 尽量只运行在专用节点。
仅仅使用 Taints 与 Tolerations,能否实现?
不能完全实现。
因为:
Toleration 只是允许 Pod 进入具有对应污点的节点,但它不会强制 Pod 选择该节点。
例如:
数据库 Pod 具有:
tolerations: - key: dedicated operator: Equal value: database effect: NoSchedule如果其他普通节点也满足调度条件,数据库 Pod 仍然可能被调度到普通节点。
所以需要同时使用:
- Taints:拒绝不符合要求的 Pod。
- Tolerations:允许指定 Pod 通过污点检查。
- Node Affinity:让指定 Pod 选择专用节点。
1. 节点配置
添加标签:
kubectl label node worker-1 \ workload=database添加污点:
kubectl taint node worker-1 \ dedicated=database:NoSchedule2. 数据库 Pod 配置
apiVersion: v1kind: Pod
metadata: name: mysql
spec: nodeSelector: workload: database
tolerations: - key: dedicated operator: Equal value: database effect: NoSchedule
containers: - name: mysql image: mysql:8.0现在形成了完整的调度控制:
数据库专用节点调度
worker-1
标签:workload=database
污点:dedicated=database
普通 Web Pod 拒绝 没有数据库污点容忍度
MySQL Pod 允许 具有 Toleration 和 NodeSelector
这就是生产环境中经常使用的专用节点隔离方案。
八、Kubernetes 默认污点
这是理解 Kubernetes 节点调度机制的重要知识。
实际上,Kubernetes 自己也会根据节点状态添加污点。
例如:
| Taint | 含义 |
|---|---|
node.kubernetes.io/not-ready | 节点未就绪 |
node.kubernetes.io/unreachable | 节点不可达 |
node.kubernetes.io/memory-pressure | 节点内存压力 |
node.kubernetes.io/disk-pressure | 节点磁盘压力 |
node.kubernetes.io/pid-pressure | 节点 PID 资源压力 |
node.kubernetes.io/network-unavailable | 节点网络不可用 |
node.kubernetes.io/unschedulable | 节点不可调度 |
这些污点会影响 Pod 的调度或驱逐。
1. 查看节点污点
kubectl describe node worker-1找到:
Taints:也可以使用:
kubectl get nodes \ -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints2. Control Plane 节点为什么不能运行普通 Pod?
很多人安装 Kubernetes 后会发现:
kubectl get nodes控制平面节点显示 Ready,但普通 Pod 通常不会被调度到上面。
原因是 Kubernetes 通常会为 Control Plane 节点设置默认污点:
node-role.kubernetes.io/control-plane:NoSchedule这个污点用于防止普通工作负载进入控制平面节点。
查看:
kubectl describe node <control-plane 节点名称 >3. 如何允许普通 Pod 进入 Control Plane?
可以删除污点:
kubectl taint nodes <control-plane 节点名称 > \ node-role.kubernetes.io/control-plane:NoSchedule-删除后,普通 Pod 就可能被调度到该节点。
注意:
生产环境一般不建议随意删除控制平面节点的默认污点,因为控制平面组件需要稳定的 CPU、内存和运行环境。
九、DaemonSet 为什么经常能够容忍系统污点?
这里有一个容易被忽略的问题:
如果节点出现了:
node.kubernetes.io/not-ready:NoExecute那么为什么某些系统级 DaemonSet Pod 仍然可能存在于这个节点上?
原因之一是:
Kubernetes 的 DaemonSet Controller 会自动为 DaemonSet Pod 添加一些内置容忍度。
常见的包括:
tolerations: - operator: Exists effect: NoSchedule
- operator: Exists effect: NoExecute这样做是为了让节点级系统组件可以运行在具有某些污点的节点上。
例如:
- 网络插件。
- 节点监控 Agent。
- 日志采集 Agent。
- 存储节点组件。
但要注意:
这只是帮助 DaemonSet Pod 通过相关污点检查,不代表节点资源、镜像、网络等问题都会自动解决。
可以查看某个 DaemonSet Pod:
kubectl get pod <pod-name> -o yaml搜索:
tolerations:你会发现它可能具有多个自动添加的容忍规则。
十、Taints 与 Tolerations 实际操作命令
这部分是 CKA 必须熟练掌握的命令。
1. 给节点添加污点
kubectl taint nodes worker-1 \ dedicated=database:NoSchedule2. 查看节点污点
kubectl describe node worker-1或者:
kubectl get nodes \ -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints3. 修改污点
先删除旧污点:
kubectl taint nodes worker-1 \ dedicated=database:NoSchedule-再添加新污点:
kubectl taint nodes worker-1 \ dedicated=redis:NoSchedule4. 删除污点
kubectl taint nodes worker-1 \ dedicated=database:NoSchedule-注意末尾的 - 表示删除对应污点。
5. 查看 Pod 容忍度
kubectl get pod nginx -o yaml查看:
spec: tolerations:6. 查看 Pod 调度失败原因
kubectl describe pod nginx重点关注:
Events: Warning FailedScheduling例如:
0/3 nodes are available:1 node(s) had untolerated taint2 Insufficient cpu表示:
- 一个节点存在 Pod 无法容忍的污点。
- 两个节点 CPU 资源不足。
十一、CKA 高频易错点
| 知识点 | 正确理解 |
|---|---|
| Taint 设置在哪里? | Node |
| Toleration 设置在哪里? | Pod |
| Toleration 是否强制调度到节点? | 不会 |
| NoSchedule 是否驱逐已有 Pod? | 不会 |
| PreferNoSchedule 是否绝对禁止调度? | 不会 |
| NoExecute 是否驱逐已有 Pod? | 会驱逐不容忍的 Pod |
| tolerationSeconds 用在哪里? | NoExecute |
| Exists 是否需要匹配 value? | 不需要 |
| 一个节点能有多个污点吗? | 可以 |
| Pod 必须容忍所有排斥性污点吗? | 是 |
| 如何删除污点? | 命令末尾添加 - |
特别记住:
Taints 是节点的排斥机制,Tolerations 是 Pod 的容忍机制,Node Affinity 是 Pod 的主动选择机制。
三者配合才能实现完整的节点调度隔离。
十二、本节知识体系总结
Taints 与 Tolerations
flowchart TB
N0["Node:Taint<br/>给节点设置污点,限制 Pod 进入"]
N1["NoSchedule<br/>禁止调度"]
N2["PreferNoSchedule<br/>尽量避免"]
N3["NoExecute<br/>禁止并驱逐"]
N4["Pod:Tolerations<br/>允许 Pod 容忍指定污点"]
N0 --> N1
N0 --> N2
N0 --> N3
N4 -.->|"容忍指定污点"| N0
关键参数
| 参数 | 作用 |
|---|---|
| key | 污点键 |
| value | 污点值 |
| effect | 污点效果 |
| Equal | 精确匹配 |
| Exists | 存在指定键即可 |
| tolerationSeconds | NoExecute 容忍时间 |