Kubernetes Pod 调度详解
Pod 是 Kubernetes 中最小的部署单元,而调度(Scheduling)决定了 Pod 被分配到哪个工作节点(Node)上运行。Kubernetes 调度器是一个控制平面组件,负责为新创建的未调度的 Pod 选择最优节点。本文将全面介绍 Pod 调度的核心概念、原理和配置方法。
调度器(kube-scheduler)
Kubernetes 默认调度器是 kube-scheduler,它以插件化、可扩展的方式工作。其主要职责是:
- 监听 API Server 中
PodSpec.nodeName为空的 Pod - 为每个待调度 Pod 按照调度算法选择一个最合适的节点
- 将绑定(Binding)结果写回 API Server,完成调度
kube-scheduler 支持多调度器并存,你可以部署自定义调度器,并通过 spec.schedulerName 指定使用哪个调度器。
调度流程
调度过程分为两个阶段:过滤(Filtering) 和 打分(Scoring),也称为"谓词"和"优先级"。
过滤阶段
过滤是所有节点的"海选"环节,只有通过所有过滤条件的节点才会进入下一阶段。常见过滤插件包括:
PodFitsResources:检查节点剩余资源(CPU、内存、扩展资源)是否满足 Pod 需求PodFitsHostPorts:检查节点上要使用的 hostPort 是否已被占用PodFitsHost:检查 Pod 的spec.nodeName是否匹配CheckNodeSelector:检查 Pod 的spec.nodeSelector是否匹配节点标签NodeAffinity:检查节点亲和性规则PodToleratesNodeTaints:检查 Pod 的容忍度能否匹配节点的污点CheckNodeUnschedulable:检查节点是否设置了spec.unschedulable=trueMatchInterPodAffinity:检查 Pod 间亲和/反亲和规则
打分阶段
通过过滤的节点进入打分环节,每个评分插件给节点打一个分数(通常 0-100),最终选择总分最高的节点。若多个节点同分,调度器会从中随机选择一个以保证负载分布。常见打分插件包括:
NodeResourcesBalancedAllocation:优先资源使用更均衡的节点NodeResourcesFit:优先资源分配后剩余资源更多的节点(LeastRequestedPriority)ImageLocality:优先已有 Pod 所需镜像的节点InterPodAffinity:根据 Pod 间亲和规则打分TaintToleration:根据污点容忍规则打分
从 Kubernetes v1.15 开始,调度器引入了调度框架(Scheduling Framework),允许开发者通过扩展点(Extension Point)集成自定义调度逻辑。
基础节点选择方式
nodeName
最直接但通常不推荐的方式。直接在 Pod 定义中指定节点名称:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
nodeName: node-01 # 直接指定节点名
containers:
- name: nginx
image: nginx缺点:节点故障、资源不足等情况下无法自动迁移,且绑定失败会导致 Pod 一直 Pending。
nodeSelector
通过节点标签选择节点。首先给节点打标签:
kubectl label nodes node-01 disktype=ssd然后在 Pod 中指定 nodeSelector:
spec:
nodeSelector:
disktype: ssdPod 只能调度到带有 disktype=ssd 标签的节点上。
节点亲和性(Node Affinity)
节点亲和性是 nodeSelector 的增强版,支持更丰富的匹配逻辑(In、NotIn、Exists、DoesNotExist、Gt、Lt)和软约束(preferred)。
节点亲和性配置在 spec.affinity.nodeAffinity 下。
requiredDuringSchedulingIgnoredDuringExecution
硬约束:Pod 必须调度到满足规则的节点上,否则无法调度。
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/e2e-az-name
operator: In
values:
- e2e-az1
- e2e-az2preferredDuringSchedulingIgnoredDuringExecution
软约束:调度器会尽量满足,但不强制。可以设置权重(weight,1-100)。
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoringDuringExecution:
- weight: 50
preference:
matchExpressions:
- key: another-node-label-key
operator: In
values:
- another-node-label-value污点(Taint)与容忍(Toleration)
污点应用于节点,表示节点拒绝某些 Pod 运行;容忍应用于 Pod,表示 Pod 可以"容忍"节点的污点。两者配合可以实现"专用节点"、"排斥特定 Pod"等高级调度策略。
设置污点
# 添加污点(key=value,效果为NoSchedule)
kubectl taint nodes node-01 key1=value1:NoSchedule
# 查看污点
kubectl describe nodes node-01 | grep Taints
# 移除污点
kubectl taint nodes node-01 key1=value1:NoSchedule-污点效果有三种:
NoSchedule:不允许新 Pod 调度到此节点,已运行 Pod 不受影响PreferNoSchedule:调度器尽量不调度到此节点,软版本NoExecute:不允许新 Pod 调度,且节点上未容忍此污点的 Pod 将被驱逐
配置容忍
在 Pod 的 spec.tolerations 中配置:
spec:
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoSchedule"
# tolerationSeconds: 3600 # 仅在 NoExecute 时有效容忍也支持 Exists 操作符(忽略 value),以及空 key 匹配所有污点。
当节点有 NoExecute 污点时,Pod 必须添加相应容忍,否则会被驱逐。通过 tolerationSeconds 可以指定容忍的时间长度,超时后仍会被驱逐。
Pod 间亲和性(Pod Affinity)与反亲和性(Pod AntiAffinity)
根据已经运行在节点上的 Pod 的标签来决定调度位置。这对于服务就近部署(降低延迟)、分散部署(提高可用性)非常有用。
配置在 spec.affinity.podAffinity 和 spec.affinity.podAntiAffinity 下。
拓扑域(topologyKey)
拓扑域指的是节点标签中代表某一"位置"的键,例如 kubernetes.io/hostname(节点)、topology.kubernetes.io/zone(可用区)、topology.kubernetes.io/region(地域)。
示例
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- backend
topologyKey: kubernetes.io/hostname
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- frontend
topologyKey: topology.kubernetes.io/zone解释:
- 硬亲和:Pod 必须调度到有
app=backend类型 Pod 的同一节点(hostname拓扑域) - 软反亲和:尽量不让同一个可用区(zone)内出现两个
app=frontend的 Pod,权重 100
优先级(Priority)与抢占(Preemption)
当集群资源不足时,可以通过 Pod 优先级和抢占机制,优先保证高优先级 Pod 运行。
PriorityClass
首先定义优先级类别:
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: high-priority
value: 1000000 # 数值越大优先级越高
globalDefault: false
description: "This priority class is for critical services."在 Pod 中指定优先级
spec:
priorityClassName: high-priority抢占机制
当高优先级 Pod 无法找到合适节点调度时,调度器会尝试驱逐一些低优先级 Pod 以释放资源。抢占过程会遵循 PodDisruptionBudget(PDB)保障,被驱逐的 Pod 会进入失败状态,但会被其控制器重建(可能再次被抢占)。
注意:抢占可能导致服务中断,生产环境请谨慎使用,并设置合理的优先级差异。
指定调度器
Kubernetes 支持多调度器。你可以部署自定义调度器(例如基于 GPU、延迟、成本等),然后在 Pod 中指定:
spec:
schedulerName: my-custom-scheduler如果未指定,默认使用 default-scheduler。
调度失败排查常用命令
# 查看 Pod 调度失败原因
kubectl describe pod <pod-name>
# 查看节点资源与标签
kubectl describe node <node-name>
# 查看节点污点
kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints
# 查看调度器日志(如果是自建集群)
kubectl logs -n kube-system kube-scheduler-control-plane常见调度失败原因:
- 0/3 nodes are available: 3 Insufficient cpu
- 0/3 nodes are available: 1 node(s) had taint
- 0/3 nodes are available: 1 node(s) didn't match pod affinity rules
- 0/3 nodes are available: 2 node(s) didn't match node selector
总结
| 调度方式 | 类型 | 适用场景 | 推荐程度 |
|---|---|---|---|
| nodeName | 硬指定 | 测试、调试 | 不推荐生产 |
| nodeSelector | 硬限制 | 简单标签筛选 | 较推荐 |
| 节点亲和(required) | 硬限制 | 复杂标签筛选 | 推荐 |
| 节点亲和(preferred) | 软偏好 | 优选节点 | 推荐 |
| 污点+容忍 | 排斥/专用 | 特殊节点、独占节点 | 推荐 |
| Pod 亲和(required) | 硬限制 | 服务就近部署 | 根据场景 |
| Pod 反亲和(required) | 硬限制 | 分散风险、高可用 | 推荐重要服务 |
| Pod 亲和/反亲和(preferred) | 软偏好 | 优化性能/可靠性 | 推荐 |
| 优先级+抢占 | 保障资源 | 关键业务保活 | 谨慎使用 |
| 自定义调度器 | 完全定制 | 特殊资源/算法 | 按需 |
理解 Pod 调度是 Kubernetes 运维和优化的核心能力。实际应用中建议优先采用 nodeSelector、节点亲和性和 Pod 反亲和性,并根据业务重要性合理使用污点/容忍与优先级机制。
