在 Kubernetes 集群中,我们很少直接指定某个 Pod 运行在哪一台物理节点上。相反,kube-scheduler 这个核心组件会根据资源、策略与约束条件,自动为每一个 Pod 挑选一个合适的节点。理解调度机制,是做好生产环境资源隔离、故障隔离与性能优化的基础。今天这一篇,我们就深入讲解节点选择(nodeSelector)、亲和性(Affinity)、污点(Taints)与容忍度(Tolerations),并配合完整实战演练。

一、调度器是如何工作的
kube-scheduler 的调度流程可以概括为两个阶段:过滤(Filtering)与打分(Scoring)。
- 过滤阶段:调度器遍历所有可用节点,排除掉那些不满足 Pod 硬性条件的节点,例如资源不足、节点带有 Pod 无法容忍的污点、节点选择器不匹配、端口冲突等。
- 打分阶段:调度器对通过过滤的节点进行评分,综合考虑资源空闲程度、亲和性偏好、拓扑分布等因素,最终选出得分最高的节点。
当没有任何节点能满足要求时,Pod 会进入 Pending 状态,直到条件发生变化。因此,遇到 Pod 一直无法调度的情况,我们首先要检查的就是调度约束是否过于严格。
二、nodeSelector:最简单的节点选择
nodeSelector 是最基础、最直观的节点选择方式。它的原理非常简单:给节点打上标签,再让 Pod 通过 nodeSelector 指定必须匹配的标签。下面我们先给节点打标签:
# 查看当前所有节点
kubectl get nodes
# 给节点 node-01 打上磁盘类型标签
kubectl label nodes node-01 disktype=ssd
# 查看节点标签是否生效
kubectl get nodes node-01 --show-labels
接着,在 Pod 的 YAML 中通过 nodeSelector 引用这个标签:
apiVersion: v1
kind: Pod
metadata:
name: nginx-ssd
spec:
containers:
- name: nginx
image: nginx:1.24
nodeSelector:
disktype: ssd
nodeSelector 的优点是简单易用,缺点也很明显:它只能做”精确等于”的硬性匹配,无法表达”优先选择”或”避免选择”这类更灵活的需求。这时候就需要引入亲和性与反亲和性。
三、亲和性:更灵活的选择策略
亲和性(Affinity)分为节点亲和性(nodeAffinity)与 Pod 亲和性(podAffinity / podAntiAffinity)。节点亲和性是对 nodeSelector 的增强,支持更多操作符和”软硬”两级策略。
apiVersion: v1
kind: Pod
metadata:
name: nginx-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
- nvme
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: zone
operator: In
values:
- zone-a
containers:
- name: nginx
image: nginx:1.24
上面的配置中,requiredDuringSchedulingIgnoredDuringExecution 是硬性要求:节点必须有 disktype 为 ssd 或 nvme 的标签,否则无法调度;preferredDuringSchedulingIgnoredDuringExecution 是软性偏好:优先调度到 zone-a 区域的节点,但如果实在没有,也不会因此调度失败。
四、污点与容忍度:反向约束
如果说 nodeSelector 和亲和性是”把 Pod 吸引到某些节点”,那么污点(Taint)与容忍度(Toleration)就是”把 Pod 从某些节点赶走”。污点标记在节点上,容忍度配置在 Pod 上,只有当 Pod 能够容忍某个污点时,它才可能被调度到带有该污点的节点上。
污点的格式为 key=value:effect,其中 effect 有三种取值:
- NoSchedule:不允许新 Pod 调度到该节点,但已运行的 Pod 不受影响。
- PreferNoSchedule:尽量不调度到该节点,属于软性限制。
- NoExecute:不允许调度,并且已运行的 Pod 如果不容忍该污点,会被驱逐。
下面演示如何给节点打污点,以及如何删除污点:
# 给 node-02 打上污点,禁止一般 Pod 调度
kubectl taint nodes node-02 dedicated=production:NoSchedule
# 查看节点上的污点
kubectl describe node node-02 | grep -i taint
# 删除污点(注意结尾的减号)
kubectl taint nodes node-02 dedicated=production:NoSchedule-
然后,在需要运行到该专用节点上的 Pod 中配置对应的容忍度:
apiVersion: v1
kind: Pod
metadata:
name: dedicated-pod
spec:
tolerations:
- key: dedicated
operator: Equal
value: production
effect: NoSchedule
containers:
- name: app
image: busybox:1.36
command: ["sleep", "3600"]
需要特别注意的是,容忍度并不代表 Pod 一定被调度到带污点的节点,它只是”允许”Pod 可以调度过去;真正决定调度到哪里的,仍然是调度器的打分逻辑。
五、实战:搭建一套专用节点
接下来我们做一个完整的实战演练。假设集群中有普通业务节点和一台专门跑 GPU 任务的节点,我们希望 GPU 任务只能跑到专用节点上,而普通业务不能占用它。首先给 GPU 节点打标签和污点:
# 打标签
kubectl label nodes gpu-node-01 accelerator=nvidia-tesla
# 打污点,普通业务无法调度
kubectl taint nodes gpu-node-01 accelerator=nvidia-tesla:NoSchedule
然后部署 GPU 任务,同时使用 nodeSelector 和容忍度:
apiVersion: v1
kind: Pod
metadata:
name: cuda-job
spec:
nodeSelector:
accelerator: nvidia-tesla
tolerations:
- key: accelerator
operator: Equal
value: nvidia-tesla
effect: NoSchedule
containers:
- name: cuda
image: nvidia/cuda:12.0.0-base-ubuntu22.04
command: ["nvidia-smi"]
这样,普通业务 Pod 因为没有容忍度,无法调度到 GPU 节点;GPU 任务通过 nodeSelector 精确落到专用节点上,实现了资源隔离。验证结果:
# 确认 Pod 调度到了正确的节点
kubectl get pods cuda-job -o wide
# 查看 Pod 的调度事件
kubectl describe pod cuda-job | grep -A 5 Events
六、常见问题与排查
-
Pod 一直处于 Pending 状态:用
kubectl describe pod <name>查看 Events,通常会看到 “0/3 nodes are available: 3 node(s) had untolerated taint…” 或 nodeSelector 不匹配的提示,据此调整配置即可。 -
打了污点后 Pod 被立即驱逐:这是因为使用了 NoExecute 且 Pod 没有对应容忍度,检查污点的 effect 类型是否符合预期。
-
容忍度配置了却不生效:注意 key、value、effect 三者必须与污点完全匹配,operator 使用 Equal 时 value 不能写错,使用 Exists 时则无需指定 value。
-
软性策略没有按预期调度:preferred 只是偏好,调度器会综合权重打分,如果硬性条件已经满足,软性偏好可能被其他因素覆盖。
七、总结
本文系统地梳理了 Kubernetes 调度机制的四大核心工具:nodeSelector 适合最简单的精确匹配;节点亲和性提供了硬性与软性两级的灵活选择;污点与容忍度则反向实现了节点隔离与专用资源保护。在实际生产中,这些机制通常会组合使用,例如给 GPU 节点打标签加污点,再给 GPU 任务同时配置 nodeSelector 与容忍度,从而实现清晰的资源边界。理解并熟练运用调度机制,是走向 K8s 生产级运维的关键一步。
下期预告:第 9 天我们将讲解资源管理——Request/Limit 与 HPA 弹性伸缩,看看如何为 Pod 合理分配资源,并让集群在流量波动时自动扩缩容,敬请期待。


















暂无评论内容