4. 默认调度算法:NodeResourcesFit、NodeName、NodeUnschedulable、NodeSelector、NodeAffinity、TaintToleration
Kubernetes 调度器在预选(Predicate)阶段会依次执行一组默认的调度算法,对每个待调度的 Pod 和所有候选 Node 进行过滤。这些算法共同决定了 Pod 能否被调度到某个节点上。本章将深入解析五个核心默认算法:NodeResourcesFit、NodeName、NodeUnschedulable、NodeSelector、NodeAffinity 和 TaintToleration。
4.1 算法执行流程与过滤逻辑
调度器在预选阶段按顺序执行这些算法,任何一个算法返回“不满足”,该节点即被排除。下图展示了默认调度算法的执行顺序与过滤关系:
执行顺序说明:调度器按图中顺序依次执行算法。NodeName 和 NodeUnschedulable 属于快速过滤,能在早期排除大量不匹配节点,减少后续算法的计算开销。
4.2 算法详解与配置实践
4.2.1 NodeName
作用:检查 Pod 是否通过 spec.nodeName 显式指定了目标节点。如果指定,则只匹配该节点;否则通过所有节点。
使用场景:调试、DaemonSet 固定调度、特殊硬件节点绑定。
apiVersion: v1
kind: Pod
metadata:
name: fixed-node-pod
spec:
nodeName: worker-01 # 直接指定节点名称
containers:
- name: nginx
image: nginx:latest
注意:使用
nodeName 会绕过调度器,即使节点不可用,Pod 也会被直接分配到该节点。生产环境应优先使用节点选择器或亲和性。
4.2.2 NodeUnschedulable
作用:检查节点是否被标记为不可调度(unschedulable)。如果节点设置了 spec.unschedulable: true,则过滤掉该节点。
管理命令:
# 将节点标记为不可调度(驱逐已有 Pod 需加 --delete-emptydir-data)
kubectl cordon node-01
# 恢复节点可调度
kubectl uncordon node-01
典型用途:节点维护、升级、故障隔离时,先 cordon 节点,确保新 Pod 不会被调度上来。
4.2.3 NodeSelector
作用:根据 Pod 中 spec.nodeSelector 定义的标签键值对,过滤出具有匹配标签的节点。
配置示例:
apiVersion: v1
kind: Pod
metadata:
name: gpu-pod
spec:
nodeSelector:
gpu-type: nvidia-tesla # 节点必须包含此标签
containers:
- name: cuda-container
image: nvidia/cuda:11.0-base
| 特性 | NodeSelector | NodeAffinity |
|---|---|---|
| 表达能力 | 简单键值对匹配 | 支持 In/NotIn/Exists/DoesNotExist/Gt/Lt 等操作符 |
| 逻辑关系 | 所有条件必须同时满足(AND) | 支持 required(硬性)和 preferred(软性) |
| 灵活性 | 低 | 高 |
| 推荐场景 | 简单标签过滤 | 复杂调度策略、多条件组合 |
4.2.4 NodeAffinity
作用:通过丰富的标签匹配规则,实现更灵活的节点选择。支持两种类型:
- requiredDuringSchedulingIgnoredDuringExecution:硬性要求,调度时必须满足,运行中忽略变化。
- preferredDuringSchedulingIgnoredDuringExecution:软性偏好,调度时尽量满足,不满足也能调度。
apiVersion: v1
kind: Pod
metadata:
name: affinity-pod
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values:
- us-east-1a
- us-east-1b
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
preference:
matchExpressions:
- key: disk-type
operator: In
values:
- ssd
containers:
- name: app
image: myapp:latest
最佳实践:将硬性约束(如合规区域)放在
required 中,将性能偏好(如 SSD 磁盘)放在 preferred 中,并合理设置 weight(1-100)来区分优先级。
4.2.5 TaintToleration
作用:节点通过 Taint(污点)拒绝 Pod 调度,Pod 通过 Toleration(容忍)声明可以容忍哪些污点。调度器检查 Pod 的容忍度是否能覆盖节点的所有 Taint。
Taint 组成:
- key:污点键
- value:污点值(可选)
- effect:污点效果,三种取值:
NoSchedule:不调度新 PodPreferNoSchedule:尽量不调度NoExecute:不调度 + 驱逐已有 Pod
# 给节点添加污点
kubectl taint nodes node-01 dedicated=gpu:NoSchedule
# 查看节点污点
kubectl describe node node-01 | grep Taints
Pod 容忍配置:
apiVersion: v1
kind: Pod
metadata:
name: gpu-workload
spec:
tolerations:
- key: "dedicated"
operator: "Equal"
value: "gpu"
effect: "NoSchedule"
containers:
- name: gpu-container
image: nvidia/cuda:11.0-base
容忍操作符:
| 操作符 | 说明 | 示例 |
|---|---|---|
| Equal | key、value、effect 全部匹配 | key: "dedicated", value: "gpu", effect: "NoSchedule" |
| Exists | 仅匹配 key 和 effect,忽略 value | key: "dedicated", effect: "NoSchedule" |
关键规则:Pod 必须容忍节点上 所有 带有
NoSchedule 或 NoExecute 效果的污点,才能被调度到该节点。如果节点有多个污点,Pod 必须为每个污点都配置对应的容忍。
4.3 算法组合实战案例
以下案例展示如何组合使用多个调度算法,实现精细化的 Pod 调度策略:
apiVersion: v1
kind: Pod
metadata:
name: production-web
spec:
# 1. NodeName 不指定,让调度器自由选择
# 2. NodeUnschedulable 由集群管理员控制,Pod 无需配置
# 3. NodeSelector 选择 SSD 节点
nodeSelector:
disk-type: ssd
# 4. NodeAffinity 偏好可用区
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/region
operator: In
values:
- us-east
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 60
preference:
matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values:
- us-east-1a
# 5. TaintToleration 容忍专用节点污点
tolerations:
- key: "dedicated"
operator: "Equal"
value: "production"
effect: "NoSchedule"
containers:
- name: web
image: nginx:latest
调度决策过程:
- 调度器获取所有 Ready 节点
- NodeName 检查:未指定,通过所有节点
- NodeUnschedulable 检查:过滤掉被 cordon 的节点
- NodeSelector 检查:只保留
disk-type=ssd的节点 - NodeAffinity 检查:必须位于
region=us-east,优先选择zone=us-east-1a - TaintToleration 检查:节点若有
dedicated=production:NoSchedule污点,Pod 必须能容忍 - 通过所有过滤的节点进入优选阶段
性能优化建议:将计算量小的算法(NodeName、NodeUnschedulable)放在前面,将计算量大的算法(NodeAffinity、TaintToleration)放在后面,可以尽早过滤掉大量不匹配节点,提升调度效率。
4.4 常见问题与排错
| 问题现象 | 可能原因 | 排查命令 |
|---|---|---|
| Pod 一直 Pending | 节点污点未容忍 / 标签不匹配 | kubectl describe pod <pod-name> 查看 Events |
| Pod 调度到错误节点 | NodeSelector 或 NodeAffinity 配置错误 | kubectl get nodes --show-labels 检查节点标签 |
| 节点无法调度新 Pod | 节点被 cordon 或存在 NoExecute 污点 | kubectl describe node <node-name> 查看 Taints 和 Conditions |
| 容忍配置不生效 | 操作符或 effect 拼写错误 | 检查 tolerations 中 key/value/effect 是否与节点污点完全一致 |