对于调度框架插件的启用或者禁用,我们可以使用安装集群时的 KubeSchedulerConfiguration 资源对象来进行配置 。下面的例子中的配置启用了一个实现了 reserve 和 preBind 扩展点的插件,并且禁用了另外一个插件,同时为插件 foo 提供了一些配置信息:
apiVersion: kubescheduler.config.k8s.io/v1kind: KubeSchedulerConfiguration---plugins:reserve:enabled:- name: foo- name: bardisabled:- name: bazpreBind:enabled:- name: foodisabled:- name: bazpluginConfig:- name: fooargs: >foo插件可以解析的任意内容
扩展的调用顺序如下:
- 如果某个扩展点没有配置对应的扩展,调度框架将使用默认插件中的扩展
- 如果为某个扩展点配置且激活了扩展,则调度框架将先调用默认插件的扩展,再调用配置中的扩展
- 默认插件的扩展始终被最先调用,然后按照 KubeSchedulerConfiguration 中扩展的激活 enabled 顺序逐个调用扩展点的扩展
- 可以先禁用默认插件的扩展,然后在 enabled 列表中的某个位置激活默认插件的扩展,这种做法可以改变默认插件的扩展被调用时的顺序
apiVersion: kubescheduler.config.k8s.io/v1kind: KubeSchedulerConfiguration---profiles:- plugins:reserve:enabled:- name: bar- name: foodisabled:- name: foo
在源码目录 pkg/scheduler/framework/plugins/examples 中有几个示范插件,我们可以参照其实现方式 。
示例其实要实现一个调度框架的插件,并不难,我们只要实现对应的扩展点,然后将插件注册到调度器中即可,下面是默认调度器在初始化的时候注册的插件:
// pkg/scheduler/algorithmprovider/registry.gofunc NewRegistry() Registry { return Registry{// FactoryMap:// New plugins are registered here.// example:// {//stateful_plugin.Name: stateful.NewStatefulMultipointExample,//fooplugin.Name: fooplugin.New,// } }}
但是可以看到默认并没有注册一些插件,所以要想让调度器能够识别我们的插件代码,就需要自己来实现一个调度器了,当然这个调度器我们完全没必要完全自己实现,直接调用默认的调度器,然后在上面的 NewRegistry() 函数中将我们的插件注册进去即可 。在 kube-scheduler 的源码文件 kubernetes/cmd/kube-scheduler/app/server.go 中有一个 NewSchedulerCommand 入口函数,其中的参数是一个类型为 Option 的列表,而这个 Option 恰好就是一个插件配置的定义:// Option configures a framework.Registry.type Option func(framework.Registry) error// NewSchedulerCommand creates a *cobra.Command object with default parameters and registryOptionsfunc NewSchedulerCommand(registryOptions ...Option) *cobra.Command {......}
所以我们完全就可以直接调用这个函数来作为我们的函数入口,并且传入我们自己实现的插件作为参数即可,而且该文件下面还有一个名为 WithPlugin 的函数可以来创建一个 Option 实例:【Kubernetes 调度器实现原理】
func WithPlugin(name string, factory runtime.PluginFactory) Option { return func(registry runtime.Registry) error {return registry.Register(name, factory) }}
所以最终我们的入口函数如下所示:package mainimport ( "k8s.io/component-base/cli" "k8s.io/kubernetes/cmd/kube-scheduler/app" "math/rand" "os" // Ensure scheme package is initialized. _ "simple-scheduler/pkg/scheduler/apis/config/schema" "simple-scheduler/pkg/scheduler/framework/plugins" "time")func main() { rand.Seed(time.Now().UTC().UnixNano()) command := app.NewSchedulerCommand(app.WithPlugin(plugins.Name, plugins.New)) code := cli.Run(command) os.Exit(code)}
其中 app.WithPlugin(sample.Name, sample.New) 就是我们接下来要实现的插件,从 WithPlugin 函数的参数也可以看出我们这里的 sample.New 必须是一个 framework.PluginFactory 类型的值,而 PluginFactory 的定义就是一个函数:type PluginFactory = func(configuration runtime.Object, f framework.Handle) (framework.Plugin, error)
所以 sample.New 实际上就是上面的这个函数,在这个函数中我们可以获取到插件中的一些数据然后进行逻辑处理即可,插件实现如下所示,我们这里只是简单获取下数据打印日志,如果你有实际需求的可以根据获取的数据就行处理即可,我们这里只是实现了 PreFilter、Filter、PreBind 三个扩展点,其他的可以用同样的方式来扩展即可:
推荐阅读
- C++ 自适应函数符和函数适配器
- 釉里红|故宫陶瓷馆:独立展柜里的瓷器,是不是都价值连城
- |历代的“礼仪玉器”:(3)玉圭
- 你可以信任由编译器优化的代码吗?
- |瓷器观音瓶(观音尊)鉴赏
- 更换玻璃升降器多少钱?玻璃升降器的故障及保养介绍
- 关于包管理器Npm、Yarn和Pnpm的一些总结
- Kubernetes 策略引擎 Kyverno 使用
- APT 如何运用JAVA注解处理器
- |清代矾红彩金鱼纹饰瓷器有什么美好寓意?