在 Kubernetes 集群管理中,调度器是决定集群资源利用率和服务性能的关键组件。本文将深入剖析 kube-scheduler 的核心工作原理、内部流转机制,并结合实际场景详解节点选择器、亲和性调度及污点容忍度的配置方法。
Kubernetes 调度核心原理
Kubernetes 集群的调度核心由 kube-scheduler 组件负责。其主要任务是根据 Pod 的资源需求、策略约束及集群当前的硬件状态,将新创建的 Pod 自动分配至最合适的 Node 节点上运行。这一过程高度灵活,支持基于资源限制、亲和性/反亲和性等维度的自定义配置。
Kube-scheduler 的工作机制
kube-scheduler 的调度流程主要包含以下五个核心步骤:
- 监听 API Server:调度器通过 Informer 机制持续监听 API Server,一旦发现有未绑定的 Pod 创建,即获取其详细元数据(如标签、资源请求)。
- 筛选可用节点:根据 Pod 的硬性约束条件(如 CPU/内存请求、特定节点标签),从集群中所有注册的 Node 中剔除不符合条件的节点。
- 计算分值:对筛选出的节点进行打分。调度算法会综合考量节点资源利用率、网络延迟等因素,计算每个节点的适配度分数。
- 选择节点:选择得分最高的节点作为最终调度目标。若多个节点分数相同,则随机选择。
- 更新 API Server:调度器将选定的 Node 信息写入 Pod 的
spec.nodeName字段,随后通知对应节点上的 Kubelet 启动容器。
调度器内部流转全解
对于需要深入了解底层机制的工程师,理解 kube-scheduler 的内部数据流转至关重要。其内部处理流程基于 client-go 的 Informer 机制和优先级队列实现:

- 事件监听与缓存:Scheduler 注册 Informer handler 监听 API Server 的 Pod 和 Node 变更事件,并将数据同步至本地缓存。
- 队列调度:Informer 将事件更新至 Scheduling Queue(调度队列)。队列分为三种:
- ActiveQ:维护基于 Pod 优先级的堆结构,调度循环每次从中取出优先级最高的 Pod。
- UnschedulableQ:存储调度失败的 Pod。
- PodBackoffQ:存储等待重试的 Pod。
- 调度循环:通过
NextPod方法从 ActiveQ 获取待调度 Pod。 - 算法匹配:运行调度算法对 Node 和 Pod 进行匹配(Predicates)和打分(Priorities)。
- 异常处理:若调度失败,调用
Error方法将 Pod 写入 UnschedulableQ。 - 退避机制:当不可调度时间超过 backoff 阈值,Pod 将转入 PodBackoffQ 等待重试。
- 异步绑定:调度器执行绑定操作时采用异步机制。它首先在缓存中创建一个 Assume Pod 模拟绑定结果(设置 NodeName),随后异步发送 Bind 请求给 API Server。在此过程中,Scheduler 会确保 Volume 已完成绑定,节点 Kubelet 接收到指令后即可在本地运行容器。
节点优选与打分策略
节点分值的计算并非固定不变,而是由可插拔的调度算法决定。默认情况下(DefaultPreemption 策略),打分主要依据以下维度:
- 资源利用率:优先选择 CPU 和内存利用率较低的节点,以保持集群负载均衡。
- Pod 分布:若节点上已运行大量 Pod,其得分会降低,以避免资源拥塞。
- 亲和性与互斥性:根据 Pod 与节点的亲和性规则(如区域、标签)提高得分;根据互斥性规则降低得分。
- 网络延迟:优先选择网络延迟较低的节点。
- Pod 优先级:高优先级(如关键业务)的 Pod 会影响节点选择的权重。
工程师可以通过配置文件或命令行参数调整这些因素的权重,甚至开发自定义调度算法以满足特定业务需求。
核心调度策略概览
Kubernetes 提供了多种调度策略以适应不同的业务场景:
- 默认调度策略 (DefaultPreemption):选择代价最小的节点。若资源不足,支持通过预选机制驱逐低优先级 Pod。
- 带优先级的调度 (Priority):基于
PriorityClass对 Pod 进行排序,确保高优先级业务优先获得资源。 - 节点亲和性 (NodeAffinity):基于节点标签匹配目标节点。
- Pod 亲和性/反亲和性 (PodAffinity/PodAntiAffinity):基于 Pod 标签决定 Pod 是部署在一起还是分散部署。
- 资源限制调度 (ResourceLimits):优先选择可用资源最多的节点。
实战:精细化调度配置
节点选择器 NodeSelector
NodeSelector 是最简单的节点约束方式,通过标签匹配将 Pod 部署到指定节点。
配置示例:
apiVersion: v1
kind: Pod
metadata:
name: nginx-ssd
spec:
containers:
- name: nginx-ssd
image: nginx:1.23.2
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
nodeSelector:
disktype: ssd
操作步骤:
- 应用配置:
kubectl apply -f nodeselector.yaml - 为节点打标:
kubectl label node k8s02 disktype=ssd - 验证调度:
kubectl describe po nginx-ssd | grep -i node
节点亲和性 NodeAffinity
相比 NodeSelector,NodeAffinity 提供了更强大的匹配逻辑,支持硬匹配(必须满足)和软匹配(尽可能满足)。
关键字段说明:
requiredDuringSchedulingIgnoredDuringExecution:硬性要求,必须满足规则。preferredDuringSchedulingIgnoredDuringExecution:软性偏好,满足则加分。operator:支持In,NotIn,Exists,DoesNotExist,Gt,Lt等逻辑运算符。
配置示例:
apiVersion: v1
kind: Pod
metadata:
name: with-node-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: env
operator: In
values:
- test
- dev
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: project
operator: In
values:
- linux
containers:
- name: with-node-affinity
image: redis:6.0.6
匹配逻辑:
- 若同时存在 NodeSelector 和 NodeAffinity,两者需同时满足。
- 若指定多组
nodeSelectorTerms,满足其中一组即可。 - 若
nodeSelectorTerms中包含多组matchExpressions,必须全部满足。
Pod 亲和性与反亲和性
Pod 亲和性用于控制 Pod 之间的部署拓扑关系,例如将通信频繁的服务部署在同一个节点或可用区。
1. Pod 亲和性
目标:将新 Pod 与目标 Pod 调度至同一拓扑域(如同一节点)。
apiVersion: v1
kind: Pod
metadata:
name: testpod02
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- myapp01 # 匹配已存在的 testpod01
topologyKey: "kubernetes.io/hostname" # 拓扑域定义为主机名
containers:
- name: testpod02
image: redis:6.2
2. Pod 反亲和性
目标:确保新 Pod 不与目标 Pod 调度至同一拓扑域(常用于高可用部署,分散副本)。
apiVersion: v1
kind: Pod
metadata:
name: testpod02
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- myapp01
topologyKey: "kubernetes.io/hostname"
containers:
- name: testpod02
image: redis:6.2
污点与容忍度
污点和容忍度是 Kubernetes 提供的节点排斥机制。污点作用于 Node,容忍度作用于 Pod。
1. 污点
污点用于阻止特定 Pod 调度到该节点,除非 Pod 定义了对应的容忍度。
Effect 类型:
- NoSchedule:仅影响新 Pod 调度,不驱逐已有 Pod。
- PreferNoSchedule:尽量不调度。
- NoExecute:既不调度新 Pod,也会驱逐不满足容忍度的已有 Pod。
操作命令:
# 设置污点
kubectl taint node [node_name] key=value:[effect]
# 示例
kubectl taint node linux02 name=linux:NoSchedule
# 查看污点
kubectl describe node linux02 | grep Taints -A 10
# 删除污点
kubectl taint node [node_name] key:[effect]-
2. 容忍度
容忍度允许 Pod 忽略节点的特定污点。配置方式包括完全匹配、不完全匹配和大范围匹配。
完全匹配示例:
tolerations:
- key: "name"
operator: "Equal"
value: "linux"
effect: "NoSchedule"
大范围匹配示例(匹配指定 key 的所有 effect):
tolerations:
- key: "name"
operator: "Exists"
匹配所有污点(慎用):
tolerations:
- operator: "Exists"
驱逐延缓时间设置:
针对 NoExecute 类型的污点,可以设置 tolerationSeconds 来延缓 Pod 的驱逐时间,给予业务优雅退出的机会。
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoExecute"
tolerationSeconds: 3600 # 保留 3600 秒后再驱逐
完整 Pod YAML 示例:
apiVersion: v1
kind: Pod
metadata:
name: ng
labels:
env: dev
spec:
containers:
- name: ng
image: nginx:1.21.0
tolerations:
- key: name
operator: Exists
effect: NoSchedule
通过掌握上述调度机制与配置策略,IT 工程师可以更加高效地管理 Kubernetes 集群资源,保障业务系统的稳定性与高性能。
