kube-scheduler 源码解析
女主宣言
本篇文章带大家了解部署在我们 HULK 容器服务 master 节点上的重要组件之一,kube-scheduler 的运行机制解读和核心代码分析,给想要阅读学习 Kubernetes 源码的同学一个参考。本文最先发布于 opsdev,转载已获取作者授权。
PS:丰富的一线技术、多元化的表现形式,尽在“HULK一线技术杂谈”,点关注哦!
前言
本文所涉及的源码为 Kubernetes 1.9,git commit id 为 925c127ec。本文前半部分讲解 scheduler 的原理,后半部分对 scheduler 源码进行分析。
1
kubernetes scheduler 基本原理
kubernetes scheduler 作为一个单独的进程部署在 master 节点上,它会 watch kube-apiserver 进程去发现 PodSpec.NodeName 为空的 Pod,然后根据指定的算法将 Pod 调度到合适的 Node 上,这一过程也叫绑定(Bind)。scheduler 的输入是需要被调度的 Pod 和 Node 的信息,输出是经过调度算法筛选出条件最优的 Node,并将该 Pod 绑定到这个 Node 上。如下图所示:
scheduler 调度算法分为两个阶段:
预选 (Predicates)
根据Predicates策略去滤掉不符合 Policies 的 Node.
优选 (Priorities)
经过 Predicates 剩下的 Node,需要经过Priorities 策略选出一个最优的 Node,并将 Pod 绑定到该 Node 上。根据下面这张调度图详细描述下:
1. 首先 scheduler 根据 predicates 集合过滤掉不符合的 Node。例如,如果 PodSpec 指定的请求资源 (resource requests),那么 scheduler 会过滤掉没有足够资源的 Node。
2. 其次 scheduler 会根据 priority functions 集合从 predicates 中过滤出来的 Node 中,选出一个最优的 Node。
算法实现:
对每一个 Node, priority functions 会计算出一个 0-10 之间的数字,表示 Pod 放到该 Node 的合适程度,其中 10 表示非常合适,0 表示不合适,priority functions 集合中的每一个函数都有一个权重 (weight),最终的值为 weight 和 priority functions 的乘积,而一个节点的 weight 就是所有 priority functions 结果的加和。例如,有两个 priority functions: priorityFunc1 和 priorityFunc2,对应的 weight 分别为 weight1 和 weight2,那么 NodeA 的最终得分是:
3. 最终,得分最高的 Node 胜出(如果有多个得分相同的 Node,会随机的选取一个 Node 作为最终胜出的 Node)。
2
kubernetes scheduler 源码分析
scheduler 的代码结构
k8s.io/kubernetes/plugin/cmd/scheduler.go 为程序入口文件 (main.go)
k8s.io/kubernetes/plugin/cmd/kube-scheduler/app/server.go 包含 scheduler 的基础配置项
除了入口函数,scheduler 的具体逻辑实现均在 k8s.io/kubernetes/plugin/pkg/scheduler 目录下,这里就不一一介绍了。
scheduler的具体实现
上面的时序图就是整个 scheduler 的具体实现逻辑。下面根据这个时序图来对 scheduler 的源码进行解析。
NewSchedulerCommand 创建一个 scheduler命令行实例,用来对 scheduler 的命令行参数进行解析校验并且包含 scheduler 程序的入口函数 Run 的函数定义。
command.Execute() 会执行命令行实例中的 options.Run 方法。
在 options.Run 中主要进行了如下的操作:
loadConfigFromFile 加载 scheduler 配置文件信息。
NewSchedulerServer 创建 scheduler server 实例,使用 scheduler 配置参数对 scheduler server 进行初始化,如:
createClients 创建一系列 client,如连接 k8s 的 client,进行 scheduler 选主的 client 及 event client.
makeLeaderElectionConfig 生成 Leader Election 配置信息 (scheduler做了 HA,可以同时运行多个实例进程,但只有一个能正常工作,如果主的 scheduler 挂了,会重新进行选举)。
makeHealthzServer 初始化 healthz server,用于健康检查。
makeMetricsServer 初始化 metrics server,用于 prometheus 性能监控。
SchedulerServer.Run 启动 SchedulerServer,用于监控还是否有 Pod 待调度,并且进行相应的调度工作。具体的代码实现:
SchedulerConfig() 创建Scheduler Config,其中关键性函数是 NewConfigFactory 和 CreateFromProvider。
NewConfigFactory 定义了 podQueue 用来存储需要被调度的 Pod,每当新的 Pod 建立后,就会将 Pod 添加到该 queue 中。
CreateFromProvider 根据 algorithm provider 名称创建一个 scheduler 配置信息。其中 GetAlgorithmProvider 则根据 provider 名称去获取指定的 provider。
scheduler 默认使用的 provider 是 DefaultProvider。它主要实现了如下数据结构:
AlgorithmProviderConfig 这个数据结构包含预选和优选相关算法 key 的集合 (一个算法对应一个key,key 是算法的名字,value 是算法的具体实现 funtion),而这些算法注册是在 scheduler/algorithmprovider/defaults/defaults.go 文件的 init() 方法中进行注册 (实现使用的是工厂模式)。 如果想了解预选和优选算法的详细信息,请参看官方文档:
https://github.com/kubernetes/community/blob/master/contributors/devel/scheduler_algorithm.md
接着往下说: 通过 GetAlgorithmProvider 得到了 provider 关联的预选和优选算法集合的 Key。然后通过调用 CreateFromKeys (预选和优选的 Key作为参数) 来获取预选和优选算法的具体实现 (funtion),并对 NewGenericScheduler 实例进行初始化,返回最终的 scheduler 配置信息。
NewFromConfig 由 Scheduler Config 创建一个 schduler。
Start up the healthz server 启动健康检查服务
Start up the metrics server 启动 metrics 服务,供 Prometheus 进行性能监控数据的抓取。
LeaderElection 如果指定选举的方式来启动scheduler,则使用这种方式来执行scheduler。(使用 CallBack 的方式执行 Run 方法。如果主的 scheduler 出现问题,还会指定优雅处理函数对其进行处理)。
下面就到了 scheduler 真正干活的逻辑了,每次调度一个 Pod 都会执行下面的 Scheduler.Run(),具体的代码如下:
WaitForCacheSync() 将最新的数据同步到 SchedulerCache 缓存中。
scheduleOne() 调度 Pod 的整体逻辑。具体的实现可以看下面代码:
NextPod() 从 PodQueue 中获取一个未绑定的Pod。
schedule(pod) 执行对应 Algorithm 的 Schedule,进行预选和优选。接口定义如下:
Schedule 主要包含如下几个重要的方法:
nodeLister.List() 获取可用的 Node 列表。
findNodesThatFit() 进行预选。
PrioritizeNodes() 进行优选。
selectHost() 如果优选出的多个得分相同的 Node,则随机选取一个 Node。
assume() 更新 SchedulerCache 中 Pod 的状态,标志该 Pod 为 scheduled,并更新到 NodeInfo 中。
bind() 调用 kube-apiserver API,将 Pod 绑定到选出的 Node,之后 Kube-apiserver 会将元数据写入 etcd 中。接口定义如下:
这样一个 Pod 绑定到 Node 的流程就完成了。
3
总结
kube-scheduler 作为 Kubernetes master上一个单独的进程提供调度服务,通过 master 指定 kube-api-server 的地址,用来 watch Pod 和 watch Node 并调用 api server bind 接口完成 Node 和 Pod 的 Bind 操作。
kube-scheduler 中维护了一个 FIFO 类型的 PodQueue cache (其实还有一种 PriorityQueue 用于指定 Pod 的优先级,需要指定参数开启,默认是 FIFO 队列),新创建的 Pod 都会被 ConfigFactory watch 到,被添加到该 PodQueue 中,每次调度都从该 PodQueue 中 NextPod() 一个即将调度的 Pod。
获取到待调度的 Pod 后,就执行 AlgorithmProvider 配置 Algorithm 的 Schedule 方法进行调度,整个调度过程分两个关键步骤:Predicates 和 Priorities,最终选出一个最适合该 Pod 的 Node。
更新 SchedulerCache 中 Pod 的状态 (AssumePod),标志该 Pod 为 scheduled,并更新到 NodeInfo 中。
调用 api server 的 Bind 接口,完成 Node 和 Pod 的 Bind 操作,如果 Bind 失败,从 SchedulerCache 中删除上一步中已经 Assumed 的 Pod。
kube-scheduler 源码解析相关推荐
- kube-proxy源码解析
kube-proxy源码解析 ipvs相对于iptables模式具备较高的性能与稳定性, 本文讲以此模式的源 码解析为主,如果想去了解iptables模式的原理,可以去参考其实现,架构上无差别. ku ...
- quartz源码解析--转
quartz源码解析(一) . http://ssuupv.blog.163.com/blog//146156722013829111028966/ 任何个人.任何企业.任何行业都会有作业调度的需求 ...
- TiKV 源码解析系列 - Raft 的优化
这篇文章转载TiDB大牛 唐刘 的博客:https://mp.weixin.qq.com/s?__biz=MzI3NDIxNTQyOQ==&mid=2247484544&idx=1&a ...
- 【Vue.js源码解析 一】-- 响应式原理
前言 笔记来源:拉勾教育 大前端高薪训练营 阅读建议:建议通过左侧导航栏进行阅读 课程目标 Vue.js 的静态成员和实例成员初始化过程 首次渲染的过程 数据响应式原理 – 最核心的特性之一 准备工作 ...
- Kafka核心源码解析 - KafkaController源码解析
在进入源码解析之前,我先来介绍一些KafkaController在Kafka集群中的作用. (1)负责监听zookeeper上所有的元数据变更请求: (2)负责topic的partition迁移任务分 ...
- Kubernetes学习笔记之Calico CNI Plugin源码解析(二)
女主宣言 今天小编继续为大家分享Kubernetes Calico CNI Plugin学习笔记,希望能对大家有所帮助. PS:丰富的一线技术.多元化的表现形式,尽在"360云计算" ...
- 【kafka】Kafka 源码解析:Group 协调管理机制
1.概述 转载:Kafka 源码解析:Group 协调管理机制 在 Kafka 的设计中,消费者一般都有一个 group 的概念(当然,也存在不属于任何 group 的消费者),将多个消费者组织成一个 ...
- 人人都能读懂的react源码解析(大厂高薪必备)
人人都能读懂的react源码解析(大厂高薪必备) 1.开篇(听说你还在艰难的啃react源码) 本教程目标是打造一门严谨(严格遵循react17核心思想).通俗易懂(提供大量流程图解,结合demo ...
- [源码解析] 机器学习参数服务器 Paracel (1)-----总体架构
[源码解析] 机器学习参数服务器 Paracel (1)-----总体架构 文章目录 [源码解析] 机器学习参数服务器 Paracel (1)-----总体架构 0x00 摘要 0x01使用 1.1 ...
最新文章
- 八月十二日,周二总结
- javascript实现汉诺塔动画效果
- lldb 调试 linux下 .net Core 总结及开源扩展 yinuo
- PHP-php.ini中文版
- 初识 JAVA IO
- FreeBSD的起源和发展
- IDC:今年全球认知和人工智能系统支出将突破125亿美元
- 案例学习BlazeDS+Spring之一(
- 从北京77元房租,说说关于房子的事
- 计算机家庭网络共享,Windows7创建家庭组实现多台电脑之间共享资源
- S5PV210芯片的DRAM控制器介绍、初始化DDR的流程分析
- Tensorflow图像处理相关操作
- 在安装anaconda3(自带python3.7)和自己安装的python2.7的win10系统中安装pymol
- opencv中cv2.warpAffine 和 cv2.warpPerspective的广泛应用
- Expat XML parser
- 快速阅读等三种读书方法
- 实用国际(XX)计量单位表
- 开发者自己搭建IM服务器所要面临的问题
- iOS ffmpeg+OpenGL播放yuv+openAL 快放 慢放 视频播放器
- Java后端实现人脸识别(基于虹软ArcSoft)
热门文章
- Python TabError inconsistent use of tabs and spaces in indentation 错误问题描述以及解决
- Java调用浏览器打开指定页面的5种方法(最全)
- Dubbo新手入门实例HelloWorld(zookeeper)
- C# 操作Sqlite
- 快速排序思路(Hoare版),代码实现
- MySQL 8下忘密码后重置密码的办法(MySQL5老方法不灵了)
- 通过Rancher部署并扩容Kubernetes集群基础篇一
- Unity GPU Instancing的使用尝试
- L2-008 最长对称字串 以下标i展开
- java中length,length(),size()区别