[译] kubernetes:kube-scheduler 调度器代码结构概述
本文翻译自 https://github.com/kubernetes/community/blob/master/contributors/devel/sig-scheduling/scheduling_code_hierarchy_overview.md
译者:胡云 Troy
调度器代码层次结构概述
介绍
调度器监视新创建的还没有分配节点的 Pod。当发现这样的 Pod 后,调度器将 Pod 调度到最适合它的节点。一般来说,调度是计算机科学中一个相当广泛的领域,它考虑了各种各样的约束和限制。调度器的每个工作负载可能需要不同的方法来实现最佳调度结果。Kubernetes 项目提供的 kube-scheduler 调度器的目标是以简单为代价提供高吞吐量。为了帮助构建调度器(默认或者定制化)和共享调度逻辑,kube-scheduler 实现了 调度框架。该框架没有提供构建新调度器的所有部分。组装一个功能齐全的单元仍然需要队列、缓存、调度算法和其他构建元素。本文档旨在描述所有单独的部分是如何组合在一起,以及它们在整个体系结构中的作用,以便开发人员能够快速了解调度器代码。
调度 Pod
默认的调度器实例运行无限期的循环,该循环(每次有 Pod 时)负责调用调度逻辑,确保 Pod 分配或重新排队以供后续处理。每个循环由一个阻塞调度周期和一个非阻塞绑定周期组成。调度周期负责运行调度算法,选择最合适的节点分配给 Pod。绑定周期确保 kube-apiserver 及时接收分配给 Pod 的节点。一个 Pod 可以立即绑定,或者在群调度中,等所有同级 Pod 分配节点之后再绑定。

图片来源 调度框架
调度周期
每个周期遵循以下步骤:
- 获取下一个调度的 Pod
- 根据提供的调度算法调度 Pod
- 如果调度 Pod 时出现
FitError错误,调度器将运行PostFilterPlugin抢占插件(如果该插件已注册),该插件将指定一个可以运行 Pod 的节点。如果抢占成功,让当前 Pod 知道分配的节点。调度器将处理错误,获取下一个 Pod 并重新开始调度。 - 如果调度算法找到了合适的节点,则将 Pod 存储到调度器缓存中(
AssumePod操作),然后按顺序运行Reserve和Permit扩展点插件。任何插件运行失败将结束当前调度周期,增加相关的指标,调度器的Error handler将处理调度错误。 - 成功运行所有扩展点后,继续绑定循环。在执行绑定循环的同时,调度周期开始处理下一个调度的 Pod(如果有的话)。
绑定周期
按相同顺序运行以下四个步骤:
- 从
Permit扩展点调用插件的 WaitOnPermit (内部 API)。扩展点的一些插件会发送操作请求去等待相应的条件(例如,等待额外的可用资源或者一组中的所有 Pod 被分配)。WaitOnPermit等待条件满足直到超时。 - 调用 PreBind 扩展点的插件
- 调用 Bind 扩展点的插件
- 调用 PostBind 扩展点的插件
任何扩展点执行失败将调用所有 Reserve 插件的 Unreserve 操作(例如,为一群 Pod 分配空闲资源)。
配置和组装调度器
调度器代码库分散在不同的地方:
- cmd/kube-scheduler/app:控制器代码的位置以及 CLI 参数的定义(遵守所有 Kubernetes 控制器的标准设定)
- pkg/scheduler:默认调度器代码库的根目录
- pkg/scheduler/core:默认调度算法的位置
- pkg/scheduler/framework:调度框架和插件
- pkg/scheduler/internal:缓存,队列和其它元素的实现
- staging/src/k8s.io/kube-scheduler:ComponentConfig API 类型的位置
- test/e2e/scheduling:调度 e2e
- test/integration/scheduler:调度集成测试
- test/integration/scheduler_perf:调度性能基准
初始启动配置
cmd/kube-scheduler/app 下的代码负责收集调度器配置和调度器初始化逻辑,它是 kube-scheduler 作为 Kubernetes 控制面运行的一部分。代码包括:
- 初始化 命令行选项(以及默认的
ComponentConfig) 和 验证 - 初始化 指标,健康检查 和 其它 handlers
- KubeSchedulerConfiguration 的读取和默认配置
- 通过插件构建
registry(in-tree, out-of-tree) - 多种选项初始化调度器,例如 profiles,算法源,pod back off,等等。
- 调用 LogOrWriteConfig,用于记录最终调度程序配置以进行调试
- 运行之前,
/configz已注册,事件广播程序已启动,领导人选举已启动,server(包含所有配置的 handlers 和 informers)已启动。
初始化之后,调度器开始运行。
更详细地说,Setup 函数完成了调度器核心流程的初始化。首先,Setup 验证传递的选项(NewSchedulerCommand() 中添加的 flags 直接设置在此选项结构的字段上)。如果传递的选项没有引发任何错误,那么它将调用 opts.Config(),用于设置最终的内部配置,包括安全服务、领导人选举、客户端,并开始解析与算法源相关的选项(比如,加载配置文件和初始化空 profiles,以及处理不推荐使用的选项像策略配置)。接下来,调用 c.Complete() 填充配置 Config 中的空值。此时,创建一个空 registry 注册 out-of-tree 插件,在 registry 中为每个插件的 New 函数添加条目。Registry 只是插件名称到插件工厂函数的映射。对于默认调度器,注册 registry 这一步什么都不做(因为 cmd/kube-chuler/scheduler.go 中的 main 函数不向 NewSchedulerCommand() 传递任何信息)。这意味着默认的插件在 scheduler.New() 中初始化。
初始化是在调度框架之外执行的,使用框架的用户可以以不同的方式初始化环境来满足自身的需求。例如,模拟器可以通过 informer 注入自身需要的对象。或者自定义的插件可以替换默认的插件。调度框架的已知使用者:
组装调度器
默认调度器实现的目录在 pkg/scheduler,调度器的各种元素在这里初始化并组合在一起:
- 默认调度选项,例如
node percentage, 初始化和最大backoff,profiles - 调度器缓存和队列
- 实例化调度的
profiles以定制框架,每个profile可以更好的安置 Pod(每个 profile 定义自身使用的插件集合) Handler函数用于获取下一个调度的 Pod(NextPod)和处理错误(Error)
在创建调度器实例的过程中,将执行以下步骤:
- 初始化调度器 缓存
- 合并 带插件的
in-tree和out-of-tree注册表 Metrics已注册- 配置器 构建调度器实例(连接缓存,插件注册表,调度算法和其它元素)
- 注册
Event handlers以允许调度器对 PV、PVC、服务和其它与调度相关的资源的更新做出反应(最终,每个插件都将定义一组事件,并对其作出反应,更详细的可参考 kubernetes/kubernetes#100347)。
下图表明了初始化后各个元素是如何连接在一起的。Event handlers 确保 Pod 在 调度队列中排队,缓存随 Pod 和节点的更新而更新(提供最新的快照 snapshot)。调度框架有对应的调度算法和绑定周期(每个框架实例有自己的 profile)。

调度框架
调度器的框架代码目前位于 pkg/scheduler/framework 下。它包含 各种插件,负责过滤和评分节点(以及其他)。常常用作调度算法的构建模块。
当 插件初始化 后,它会传递一个 框架 handler,该框架 handler 提供访问和/或操作 pod、节点、clientset、事件记录器和每个插件实现其功能所需的其他 handler 的接口。
调度缓存
缓存负责记录集群的最新状态。保存节点和 assumed Pod 以及 Pod 和 images 的状态。缓存提供了协调 Pod 和节点对象(调用 event handlers)的方法,使集群的状态保持最新。允许在每个调度周期开始时使用最新状态(在运行调度算法时固定集群状态)更新集群的快照。
缓存还允许运行假定的操作,该操作将 Pod 临时存储在缓存中,使得 Pod 看起来像已经在快照的所有消费者的指定节点上运行那样。假定操作忽视了 kube-apiserver 和 Pod 实际更新的时间,从而增加调度器的吞吐量。
以下操作使用假定的 Pod 进行操作:
AssumePod:用于通知调度算法找到可行的节点,以便在当前 Pod 进入绑定周期时可以调度下一个 PodFinishBinding:用于发出绑定完成的信号,以便可以将 Pod 从假定 Pod 列表中删除ForgetPod:从假定的 Pod 列表中删除 Pod,用于绑定周期中未能成功处理 Pod 的情况(例如,Reserve,Permit,PreBind或者Bind评估)
缓存跟踪以下三个指标:
scheduler_cache_size_assumed_pods:在假定 Pod 列表中的 Pod 数量scheduler_cache_size_pods:在缓存中的 Pod 数量scheduler_cache_size_nodes:在缓存中的节点数量
快照
快照 捕获集群的状态,其中包含集群中所有节点和每个节点上对象的信息。即节点对象、分配在每个节点上的 Pod、每个节点上所有 Pod 的请求资源、节点的可分配资源、拉取的镜像以及做出调度决策所需的其他信息。每次调度 Pod 时,都会捕获集群当前状态的快照。这样是为了避免在处理插件时更改 Pod 或节点时导致的数据不一致,因为一些插件可能会获得不同的集群状态。
配置器
配置器 通过将插件、缓存、队列、handlers 和其他元素连接在一起来构建调度器实例。每个 profile 都使用自己的框架(所有框架共享 informers,event recorders 等)进行 初始化。
也可以让配置器根据 策略文件 创建实例。不过,这种方法已被弃用,最终将从配置中删除。只保留调度器配置作为提供给配置器配置的唯一方式。
默认调度算法
代码库定义了 ScheduleAlgorithm 接口。任何该接口的实现都可以用作调度算法。这里有两种方法:
Schedule:负责使用从PreFilter到NormalizeScore扩展点的插件来调度 Pod,提供包含调度决策(最合适的节点)和附带信息的 ScheduleResult,其中附带信息包括评估了多少节点以及发现有多少节点可用于调度。Extenders: 当前仅用于测试
默认算法实现的每个周期包括:
- 从调度缓存中获取 当前快照
- 过滤掉所有无法调度 Pod 的节点
- 运行 PreFilter 插件(预处理阶段,例如计算 Pod 亲和性关系)
- 并行运算
Filter 插件:过滤掉不满足 Pod 限制条件(例如资源,节点亲和性等)的节点,包括运行Filter 扩展器 - 运行
PostFilter 插件如果没有节点满足要调度的 Pod
- 在 Pod 至少有两个可行节点可以调度的情况下,运行 scoring 插件:
- 运行 PreScore 插件(预处理阶段)
- 并行运行 Score 插件:每个节点都有一个分数向量(每个坐标对应一个插件)
- 运行 NormalizeScore 插件:给所有插件打分,间隔为 [0, 100]
- 计算每个节点的 权重分数 (每个分数插件都可以分配一个权重,指示其分数在多大程度上优于其他插件)
- 运行 打分扩展器,并且将分数计入每个节点的总分
- 选择 并 返回 得分最高的节点。如果只有一个可供调度的节点则跳过
Prescore,Score和NormalizeScore扩展点,并且立即返回调度的节点。如果没有可供调度的节点,将结果返回给调度器。
值得注意的是:
- 如果插件提供
score normalization,当调用 ScoreExtensions() 时,插件需要返回非 nil
[译] kubernetes:kube-scheduler 调度器代码结构概述的更多相关文章
- Kubernetes集群调度器原理剖析及思考
简述 云环境或者计算仓库级别(将整个数据中心当做单个计算池)的集群管理系统通常会定义出工作负载的规范,并使用调度器将工作负载放置到集群恰当的位置.好的调度器可以让集群的工作处理更高效,同时提高资源利用 ...
- quartz2.3.0(十二)通过RMI协议向Scheduler调度器远程添加job任务
此代码示例通过RMI协议向Scheduler调度器远程添加job任务. 代码文件包括:job任务类(SimpleJob.java).RMI服务端server类(RemoteServerExample. ...
- Kubernetes K8S之调度器kube-scheduler详解
Kubernetes K8S之调度器kube-scheduler概述与详解 kube-scheduler调度概述 在 Kubernetes 中,调度是指将 Pod 放置到合适的 Node 节点上,然后 ...
- scrapy 源码解析 (四):启动流程源码分析(四) Scheduler调度器
Scheduler调度器 对ExecutionEngine执行引擎篇出现的Scheduler进行展开.Scheduler用于控制Request对象的存储和获取,并提供了过滤重复Request的功能. ...
- Kubernetes 学习20调度器,预选策略及优选函数
一.概述 1.k8s集群中能运行pod资源的其实就是我们所谓的节点,也称为工作节点.master从本质上来讲,他其实是运行整个集群的控制平面组件的比如apiserver,scheal,controlm ...
- kubernetes机理之调度器以及控制器
一 了解调度器 1.1 调度器是如何将一个pod调度到节点上的 我们都已然知晓了,API服务器不会主动的去创建pod,只是拉起系统组件,这些组件订阅资源状态的通知,之后创建相应的资源,而负责调度po ...
- 图解kubernetes调度器SchedulerExtender扩展
在kubernetes的scheduler调度器的设计中为用户预留了两种扩展机制SchdulerExtender与Framework,本文主要浅谈一下SchdulerExtender的实现, 因为还有 ...
- 图解kubernetes调度器抢占流程与算法设计
抢占调度是分布式调度中一种常见的设计,其核心目标是当不能为高优先级的任务分配资源的时候,会通过抢占低优先级的任务来进行高优先级的调度,本文主要学习k8s的抢占调度以及里面的一些有趣的算法 1. 抢占调 ...
- Kubernetes 调度器实现初探
Kubernetes 调度器 Kubernetes 是一个基于容器的分布式调度器,实现了自己的调度模块.在Kubernetes集群中,调度器作为一个独立模块通过pod运行.从几个方面介绍Kuberne ...
- 图解kubernetes调度器SchedulerCache核心源码实现
SchedulerCache是kubernetes scheduler中负责本地数据缓存的核心数据结构, 其实现了Cache接口,负责存储从apiserver获取的数据,提供给Scheduler调度器 ...
随机推荐
- 配置tabBar导航菜单与open跳转差异
"tabBar": { "color": "#333", "selectedColor": ...
- FolkMQ 内存型消息中间件,v1.0.21 发布
简介 采用 "多路复用" + "内存运行" + "快照持久化" + "Broker 集群模式"(可选)+ 基于 Sock ...
- 专业的字节码查看工具——jclasslib
下载地址: GitHub地址:点击下方蓝色链接即可. https://github.com/ingokegel/jclasslib/releases/download/6.0.4/jclasslib_ ...
- ASR项目实战-产品分析
分析Google.讯飞.百度.阿里.QQ.搜狗等大厂的ASR服务,可以罗列出一款ASR服务所需要具备的能力. 产品分类 ASR云服务产品,从用户体验.时效性.音频时长,可以划分为如下几类: 实时短音频 ...
- 复现YOLO5所遇到的问题
一. 解决方案: 由于没有影响模型继续运行,理解为简单的warning.根据查询问题,推断是由于 pytorch和torchvision的版本原因导致的. 二. 解决方案: 由于没有影响模型继续运行, ...
- PySimpleGUI 使用浅谈
1. 背景 PySimpleGUI是一个简单易用的Python GUI库,它提供了一种直观且快速创建图形用户界面的方式. 2. 安装 pip install PySimpleGUI 3. PySimp ...
- STM32CubeMX教程9 USART/UART 异步通信
1.准备材料 开发板(正点原子stm32f407探索者开发板V2.4) ST-LINK/V2驱动 STM32CubeMX软件(Version 6.10.0) keil µVision5 IDE(MDK ...
- 第十三部分_awk
一.awk介绍 1. awk概述 awk是一种编程语言,主要用于在linux/unix下对文本和数据进行处理,是linux/unix下的一个工具.数据可以来自标准输入.一个或多个文件,或其它命令的输出 ...
- 干货分享丨轻松玩转 Huawei LiteOS 传感框架
摘要:LiteOS传感框架将物联网终端设备上不同类型的传感器统一管理,通过抽象不同类型传感器接口,屏蔽其硬件细节,做到"硬件"无关性,非常方便于物联网设备的开发.维护和功能扩展. ...
- WSDM Cup 2020大赛金牌参赛方案全解析
近日,在美国休斯敦闭幕的第13届网络搜索与数据挖掘国际会议(WSDM 2020)上,华为云语音语义创新Lab带领来自华南理工大学.华中科技大学.江南大学.武汉大学的四位学生组成的联合团队"X ...