为了深入学习 kube-scheduler,本系列从源码和实战角度深度学 习 kube-scheduler,该系列一共分6篇文章,如下:
- kube-scheduler 整体架构
- 初始化一个 scheduler
- 一个 Pod 是如何被调度的
- 如何开发一个属于自己的scheduler插件
- 开发一个 prefilter 扩展点的插件
- 开发一个 socre 扩展点的插件
上一篇文章我们讲了一个 Pod 是如何被感知到需要调度和如何被调度的,其中在调度过程中寻找合适的 Node 用的都是内置默认的插件,其实 kube-scheduler 是可以扩展的。那么为什么要扩展呢?原因在于默认的插件算法可能并不能满足你的需要,比如我想要在preFilter 阶段就过滤掉带某些标签的节点,又或者我想根据节点实际的资源使用率来打分而不是当前已经分配的资源,那么默认的 kube-scheduler 是无法满足你的要求的,这时候我们就需要开发一个自己的插件对 kube-scheduler 进行扩展。kube-scheduler 扩展的方式主要有下面两种:
- 使用现有 kube-scheduler 提供的 extender 机制,进行扩展;这种方式就是开发 filter、score、bind的独立运行程序,这种模式允许你使用任何语言开发,开发的程序可以运行在任何 kube-scheduler 可以通过 http 访问访问到的地方;这种模式的优点就是 kube-scheduler 解耦,无需改变 kube-scheduler 代码,只需要增加配置文件即可;但是缺点也很明显,kube-scheduler 需要通过调用API的方式来访问扩展,所以会产生网络IO,这是很重的操作,会降低调度效率,并且还强依赖外部扩展的稳定性
- 通过调度框架(Scheduling Framework)进行扩展,Kubernetes v1.15 版本中引入了可插拔架构的调度框架,使得定制调度器这个任务变得更加的容易;这种模式只需要在现有扩展点的某个位置插入自定义的插件即可,还可以关闭默认的插件。这种模式也不需要修改现有的 kube-scheduler 框架代码,跟上一种模式不同的是,他是运行在 kube-scheduler 框架中的,就跟默认的内置插件没有区别,所以不需要 API 调用,稳定性好,效率也高。如下图,每一个箭头都是一个扩展点,每一个扩展点都可以插入自定义插件
如我们可以在 filter 扩展点插入自己的插件,如下图
本文就根据第二种模式详细讲讲,开发一个自定义的插件需要哪些步骤。
我们先回顾下几个重要的概念:scheduler, framework, registry
他们之间的关系我用下图来表示
-
scheduler
是一个调度器,它实现了整体调度逻辑,如在适当位置执行适当的扩展点,一个 Pod 调度失败了需要做什么处理,记录每一个调度情况暴露出 metric 方便外界对 scheduler 的监控等等。scheduler 是串联整个调度流程的。 -
Profiles
scheduler 的一个成员,就是如下的一个Map
// pkg/scheduler/profile/profile.go
// Map holds frameworks indexed by scheduler name.
type Map map[string]framework.Framework
这个 map 的 key 是 scheduler name, vaule 是 Framework。我们一般在使用 kube-scheduler 时,没有对 kube-scheduler 或他配置文件做修改,此时这个 map 的 key 就只有默认的"default-scheduler",但是我们现在要开发自己的插件,我们可以在配置文件中定义新的 scheduler name,在这个 scheduler name 中引用自己开发的插件,我们看下下面的配置
apiVersion: kubescheduler.config.k8s.io/v1beta2
kind: KubeSchedulerConfiguration
leaderElection:
leaderElect: true
clientConnection:
kubeconfig: "/etc/kubernetes/scheduler.conf"
profiles:
- schedulerName: my-scheduler-1
plugins:
preFilter:
enabled:
// 我们在 preFilter 扩展点的 开发的 zoneLabel 插件
- name: zoneLabel
- schedulerName: my-scheduler-2