女主宣言

本篇文章带大家了解部署在我们 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 进行初始化,如:

  1. createClients 创建一系列 client,如连接 k8s 的 client,进行 scheduler 选主的 client 及 event client.

  2. makeLeaderElectionConfig 生成 Leader Election 配置信息 (scheduler做了 HA,可以同时运行多个实例进程,但只有一个能正常工作,如果主的 scheduler 挂了,会重新进行选举)。

  3. makeHealthzServer 初始化 healthz server,用于健康检查。

  4. makeMetricsServer 初始化 metrics server,用于 prometheus 性能监控。

  • SchedulerServer.Run 启动 SchedulerServer,用于监控还是否有 Pod 待调度,并且进行相应的调度工作。具体的代码实现:


  • SchedulerConfig() 创建Scheduler Config,其中关键性函数是 NewConfigFactory 和 CreateFromProvider。

  1. NewConfigFactory 定义了 podQueue 用来存储需要被调度的 Pod,每当新的 Pod 建立后,就会将 Pod 添加到该 queue 中。

  2. 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 主要包含如下几个重要的方法:

  1. nodeLister.List() 获取可用的 Node 列表。

  2. findNodesThatFit() 进行预选。

  3. PrioritizeNodes() 进行优选。

  4. 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 源码解析相关推荐

  1. kube-proxy源码解析

    kube-proxy源码解析 ipvs相对于iptables模式具备较高的性能与稳定性, 本文讲以此模式的源 码解析为主,如果想去了解iptables模式的原理,可以去参考其实现,架构上无差别. ku ...

  2. quartz源码解析--转

    quartz源码解析(一)  . http://ssuupv.blog.163.com/blog//146156722013829111028966/ 任何个人.任何企业.任何行业都会有作业调度的需求 ...

  3. TiKV 源码解析系列 - Raft 的优化

    这篇文章转载TiDB大牛 唐刘 的博客:https://mp.weixin.qq.com/s?__biz=MzI3NDIxNTQyOQ==&mid=2247484544&idx=1&a ...

  4. 【Vue.js源码解析 一】-- 响应式原理

    前言 笔记来源:拉勾教育 大前端高薪训练营 阅读建议:建议通过左侧导航栏进行阅读 课程目标 Vue.js 的静态成员和实例成员初始化过程 首次渲染的过程 数据响应式原理 – 最核心的特性之一 准备工作 ...

  5. Kafka核心源码解析 - KafkaController源码解析

    在进入源码解析之前,我先来介绍一些KafkaController在Kafka集群中的作用. (1)负责监听zookeeper上所有的元数据变更请求: (2)负责topic的partition迁移任务分 ...

  6. Kubernetes学习笔记之Calico CNI Plugin源码解析(二)

    女主宣言 今天小编继续为大家分享Kubernetes Calico CNI Plugin学习笔记,希望能对大家有所帮助. PS:丰富的一线技术.多元化的表现形式,尽在"360云计算" ...

  7. 【kafka】Kafka 源码解析:Group 协调管理机制

    1.概述 转载:Kafka 源码解析:Group 协调管理机制 在 Kafka 的设计中,消费者一般都有一个 group 的概念(当然,也存在不属于任何 group 的消费者),将多个消费者组织成一个 ...

  8. 人人都能读懂的react源码解析(大厂高薪必备)

    人人都能读懂的react源码解析(大厂高薪必备) 1.开篇(听说你还在艰难的啃react源码) ​ 本教程目标是打造一门严谨(严格遵循react17核心思想).通俗易懂(提供大量流程图解,结合demo ...

  9. [源码解析] 机器学习参数服务器 Paracel (1)-----总体架构

    [源码解析] 机器学习参数服务器 Paracel (1)-----总体架构 文章目录 [源码解析] 机器学习参数服务器 Paracel (1)-----总体架构 0x00 摘要 0x01使用 1.1 ...

最新文章

  1. 八月十二日,周二总结
  2. javascript实现汉诺塔动画效果
  3. lldb 调试 linux下 .net Core 总结及开源扩展 yinuo
  4. PHP-php.ini中文版
  5. 初识 JAVA IO
  6. FreeBSD的起源和发展
  7. IDC:今年全球认知和人工智能系统支出将突破125亿美元
  8. 案例学习BlazeDS+Spring之一(
  9. 从北京77元房租,说说关于房子的事
  10. 计算机家庭网络共享,Windows7创建家庭组实现多台电脑之间共享资源
  11. S5PV210芯片的DRAM控制器介绍、初始化DDR的流程分析
  12. Tensorflow图像处理相关操作
  13. 在安装anaconda3(自带python3.7)和自己安装的python2.7的win10系统中安装pymol
  14. opencv中cv2.warpAffine 和 cv2.warpPerspective的广泛应用
  15. Expat XML parser
  16. 快速阅读等三种读书方法
  17. 实用国际(XX)计量单位表
  18. 开发者自己搭建IM服务器所要面临的问题
  19. iOS ffmpeg+OpenGL播放yuv+openAL 快放 慢放 视频播放器
  20. Java后端实现人脸识别(基于虹软ArcSoft)

热门文章

  1. Python TabError inconsistent use of tabs and spaces in indentation 错误问题描述以及解决
  2. Java调用浏览器打开指定页面的5种方法(最全)
  3. Dubbo新手入门实例HelloWorld(zookeeper)
  4. C# 操作Sqlite
  5. 快速排序思路(Hoare版),代码实现
  6. MySQL 8下忘密码后重置密码的办法(MySQL5老方法不灵了)
  7. 通过Rancher部署并扩容Kubernetes集群基础篇一
  8. Unity GPU Instancing的使用尝试
  9. L2-008 最长对称字串 以下标i展开
  10. java中length,length(),size()区别