调度框架
基于kubernetes v1.32.0
在启动kube-scheduler的时候可以通过--config来指定scheduler运行的配置(此时--kubeconfig会被忽略)。
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
clientConnection:
kubeconfig: /etc/kubernetes/scheduler.conf
leaderElection:
leaderElect: false
profiles:
- schedulerName: my-scheduler
plugins:
score:
enabled:
- name: MyPlugin
disabled:
- name: "*"
上面的scheduler配置文件中:
apiVersion:API对象的版本,由GroupName和Version组成,可以在Configuration APIs | Kubernetes中查询,也可以在对应代码仓库的staging/src/k8s.io/kube-scheduler中检索GroupName获得。kubeconfig:用于和apiserver交互,使用kubectl config view --raw生成的配置就是可用的。leaderElection:决定是否选举主节点。profiles:调度器配置,每个数组元素最终都会被读取解析成KubeSchedulerProfile对象(staging/src/k8s.io/kube-scheduler/config/v1/types.go)。
framework配置解析
kube-scheduler启动的时候将配置文件中的profiles解析成一个KubeSchedulerProfile的数组,每个KubeSchedulerProfile代表一个调度器(默认调度器名称为default-scheduler)。kube-scheduler为数组中的每个调度器新建一个framework,其主要调度流程均由framework下的插件负责,每个调度流程呈现在配置文件中就是profiles[*]/plugins下的一个字段,该字段包含enabled和disabled,分别表示启用的插件和不启用的插件。比如上面的例子,在my-scheduler这个调度器的score调度流程中会启用MyPlugin这个插件,不启用除此之外的其他插件。
framework由NewFramework(pkg/scheduler/framework/runtime/framework.go)方法创建。NewFramework的Registry类型入参中包含了所有插件的{名称,构造方法}组合。生成framework时代码会先根据构造方法生成这个插件的实例,用map进行存储,然后遍历每个调度流程下的插件(本例profiles[*]/plugins/score下所有的插件),如果有插件在enabled数组中则需要检查该插件实例是否实现了对应的接口。
插件的注册
一个framework代表一个调度器,一个plugin(插件)表示一个调度功能(或者叫约束?),pod在调度的时候需要满足的某个约束条件的判别就是由插件来完成的。插件的实现位于pkg/scheduler/framework/plugins,每个插件必须实现k8s.io/kubernetes/pkg/scheduler/framework包下的Plugin接口,根据涉及的调度流程额外实现对应的接口(对应的接口查看pkg/scheduler/framework/interface.go)。
编写完成后需要在pkg/scheduler/framework/plugins/registry.go的NewInTreeRegistry方法中将插件添加到Registry中,Registry随后将插件注册到framework中。
除此之外,Registry.Merge也可以添加对应的插件,但该调用路径最终指向了test。而NewInTreeRegistry的调用路径最终指向了kube-scheduler的NewSchedulerCommand方法,该方法在kube-scheduler启动时并没有传入参数。因此,当前无法像crd那样对kube-scheduler进行扩展(实践中...)。
插件的使用
补充实践中...