调度器:集群资源的大脑
在 Kubernetes 中,Scheduler(kube-scheduler)是负责将新创建的 Pod 分配到合适工作节点(Node)的核心组件。当一个 Pod 成功通过 API Server 的验证并持久化到 etcd 时,如果其 spec.nodeName 为空且 schedulerName 匹配,调度器就会启动一轮调度周期(Scheduling Cycle),为 Pod 寻找最优的节点。这个看似简单的“塞箱子”问题,实际上是一个多目标约束优化问题——在满足数百个软硬约束的同时,实现资源的高效利用、应用的亲和分布、故障域的容错分布等。
调度框架:两阶段架构
Kubernetes 的调度过程由两大部分组成:调度周期(Scheduling Cycle)和绑定周期(Binding Cycle)。调度周期是确定 Pod 应该放在哪个节点上的过程,绑定周期是将该决策持久化到 API Server(更新 Pod 的 spec.nodeName)的过程。调度周期可以并行执行(多个 Pod 同时调度),绑定周期从队列中串行执行(减少 API 冲突)。
一个完整的调度周期内,又依次经过两个阶段的过滤逻辑:
过滤阶段(Filtering):调度器遍历所有注册的过滤插件(Predicates/NodePlugin),剔除所有不满足硬约束的节点,得到“可行节点列表”。在 Kubernetes 1.23+ 版本中,原 Predicates 算法已整合到 Scheduling Framework 的 Filter 插件中。核心过滤包括:节点资源是否满足 Pod 的请求(Pod 的 requests.cpu/memory 总和小于 Node 的可分配资源)、节点是否有匹配的标签(NodeSelector/NodeAffinity)、节点是否有不可容忍的污点(Toleration)、卷冲突检查等。
打分阶段(Scoring):对过滤后的每个可行节点运行打分插件,每个插件给出0-100的分数,最终加权求和得到总分,分最高者为调度结果。常用打分插件包括:LeastRequestedPriority(倾向于分配到剩余资源最多的节点)、MostRequestedPriority(倾向于分配到已分配资源更多的节点以便集中装箱)、BalancedResourceAllocation(考虑CPU和内存分配比例的均衡性)、ImageLocalityPriority(节点已存在容器镜像时加分)、InterPodAffinityPriority(实现Pod间亲和/反亲和约束)。
亲和、污点与容忍:精细调度控制
Kubernetes 提供三层渐进式的调度约束机制,赋予运维人员表达几乎任何部署偏好规则的能力。
NodeAffinity(节点亲和):按节点标签引导调度。requiredDuringSchedulingIgnoredDuringExecution 是硬约束——不满足则 Pod 无法调度;preferredDuringSchedulingIgnoredDuringExecution 是软约束——按权重(1-100)加分。这与 NodeSelector(简单的键值等值匹配)相比更灵活,支持 In、NotIn、Exists、Gt、Lt 等多种操作符。
PodAffinity/AntiAffinity(Pod 间亲和/反亲和):按已运行的其他 Pod 的位置引导调度。许多分布式数据库(如 CockroachDB、etcd、Kafka 集群)通过 required PodAntiAffinity 确保每个副本被调度到不同的节点或可用区。对于强一致性要求的组件,使用 required 反亲和+拓扑键(topologyKey: topology.kubernetes.io/zone)是生产标配。
Taints and Tolerations(污点与容忍):与亲和相反,污点使节点“排斥”不匹配的 Pod。当节点被标记为 Taint: key=value:NoSchedule,只有拥有对应 Toleration 的 Pod 才能被调度到此节点。这种机制常用于:专用节点池(如 GPU 节点只允许 GPU 工作负载)、节点排空(Drain,用于维护时打 NoExecute 污点驱逐 Pod)、硬件特性隔离。
优先级与抢占机制
当集群资源不足时,低优先级的 Pod 可能因为无法调度而长时间处于 Pending 状态。Kubernetes 通过 PriorityClass 和 Preemption 机制解决这一问题。
PriorityClass 资源定义优先级值(范围1到1,000,000,000),每个 Pod 可指定 priorityClassName。高优先级 Pod 入队时排在队首(优先被调度)。当高优先级 Pod 在所有节点都无法调度(没有节点满足硬约束)时,抢占机制尝试将低优先级 Pod 从某个节点驱逐(Evict 到 Pending 状态),并预留节点资源等待高优 Pod 调度进入。抢占者的决策过程从最廉价的节点开始,按升序寻找“牺牲品”。
抢占有破坏性(会导致被抢占 Pod 在下次重调度前短暂不可用),因此部署严格的 PodDisruptionBudget(PDB)和优先级值的审核制度是必要的。实践中建议:core-system 组件(CoreDNS、metrics-server)优先级高于100,000,000;关键业务 Pod 高于1,000,000;普通业务 Pod 使用默认级别(0)或不指定。
多调度器与自定义调度
Kubernetes 支持在集群中运行多个调度器实例。Pod 通过设置 spec.schedulerName 指定由哪个调度器负责。当 schedulerName 不是默认调度器时,内置调度器会忽略该 Pod。
实现自定义调度器的方法主要有三种:
一是 Scheduler Extender:与 kube-scheduler 通过 Webhook 集成,在默认调度的过滤和打分阶段加入自定义逻辑。优点是不需要运行一个新进程,只需在 kube-scheduler 配置文件中指定 Extender 的 URL 和过滤/打分的节点列表。缺点是 Extender 是阻塞 HTTP 调用,超时配置不当可能导致整个调度流程延迟。
二是 直接实现调度器:编写独立的 Go 程序,通过 Watch API 监听默认调度器未认领的 Pod(通过 schedulerName 过滤),自行实现调度逻辑并调用 Binding API 提交节点分配。这是最灵活的方式,但需要自行处理并发、错误重试和抢占逻辑。
三是 Scheduling Framework + 自定义插件:Kubernetes 1.18 引入了可插拔的 Scheduling Framework,允许开发者通过 QueueSort/Filter/Score/Reserve/PreBind/Bind 等扩展点注册自定义插件,并与内置插件共存于 default-scheduler 二进制中。这种方式兼具灵活性和集成度,是社区推荐的方法。
开源项目如 YuniKorn(来自 Apache,支持大数据批处理)、Volcano(华为开源,面向 AI 训练/大数据的批调度)提供了面向大规模批量计算场景的完整调度解决方案。Volcano 完善了 Gang-scheduling(全有或全无调度)、Fairshare(公平份额)、Queue 管理等 K8s 默认调度器不具备的批调度特性。
生产环境调度优化要点
在大型集群(数百到数千节点)中,调度器可能本身成为性能瓶颈——每秒钟需要调度的 Pod 数量可能是数百到数千。kube-scheduler 的 PercentageOfNodesToScore 参数(默认值根据节点数动态调整,约5-50%)控制了一轮评分阶段扫描的节点比例。当集群节点数超过5000时,这个默认下限可能不足导致调度质量下降;当节点数小于100时可以设低以扫更多节点。
此外,集群自动扩缩容(Cluster Autoscaler, CA)的调度决策也会间接影响 Pod Pending——如果待调度 Pod 所需的最小节点规格(加上现有节点的 PDB 约束)无法在任何现有节点满足,CA 会触发节点添加。Pod的 resource.requests 配置准确性和 MaxSurge/MaxUnavailable(Rolling Update 策略中控制的新旧 Pod 比例)直接影响节点的推荐扩缩容行为。
容量规划中的一个常见误区:将所有 Pod 的 requests 设得远远低于实际使用量以减少“浪费”。这种做法会在实际业务高峰到来时导致节点 CPU 饱和——Linux CFS(完全公平调度器)的 CPU 限流机制会节流容器,导致响应延迟飙升,而节点资源监控(基于 requests 不会显示任何异常)。基于历史 Prometheus 数据的 VPA(Vertical Pod Autoscaler)建议值来设定 requests,一半是一个不错的起点。
调度对应用架构的反作用
Kubernetes 调度机制的特性深刻影响着应用架构的设计原则:
PodDisruptionBudget 约束 + required 反亲和 + 多可用区部署 = 应用具备区域级故障转移能力。
Spread Constraints(从 K8s 1.27 开始 GA)—— maxSkew 机制可以将 Pod 尽可能均匀地分布在指定拓扑域(节点/可用区)上,替代复杂的 Pod 间反亲和手动计算。
用 Failure 模式模拟工具(如 Chaos Mesh、LitmusChaos),结合调度的约束规则,可以验证在节点可用性扰动下应用的调度弹性。
Kubernetes 的调度机制将基础设施与上层应用无缝衔接,它的发展正在从简单的资源分配器向具有容量预测、智能灰度上线和多维资源博弈的自适应系统演进。理解调度逻辑的核心与边界,是构建可靠云原生系统的底层功。

发表评论 取消回复