在kubernetes的scheduler调度器的设计中为用户预留了两种扩展机制SchdulerExtender与Framework,本文主要浅谈一下SchdulerExtender的实现, 因为还有一篇Framework, 所以本文的k8s代码切到1.18版本
1. 设计思路
1.1 实现机制
SchdulerExtender是kubernets外部扩展方式,用户可以根据需求独立构建调度服务,实现对应的远程调用接口(目前是http), scheduler在调度的对应阶段会根据用户定义的资源和接口来进行远程调用,对应的service根据自己的资源数据和scheduler传递过来的中间调度结果来进行决策
1.2 服务插拔
extender只需要实现对应插件的接口,并编写yaml文件来进行注册对应的服务接口,就可以实现scheduler的扩展,不需要修改任何调度器的代码,即可实现调度插件的插拔
1.3 资源存储
因为是独立的服务,extender可以实现自定义资源的存储与获取,甚至可以不依赖于etcd使用第三方的存储来进行资源的存储,主要是用于kubernetes中不支持的那些资源的调度扩展
2. SchedulerExtender
2.1 接口与实现
2.1.1 接口声明
Scheduler主要用于扩展
type SchedulerExtender interface {
// Name returns a unique name that identifies the extender.
Name() string
//预选阶段, 进行筛选
Filter(pod *v1.Pod, nodes []*v1.Node) (filteredNodes []*v1.Node, failedNodesMap extenderv1.FailedNodesMap, err error)
// 优选阶段,参与优选评分
Prioritize(pod *v1.Pod, nodes []*v1.Node) (hostPriorities *extenderv1.HostPriorityList, weight int64, err error)
// extender对pod指向绑定操作
Bind(binding *v1.Binding) error
// 扩展是否支持bind
IsBinder() bool
// 是否对对应的pod的资源感兴趣
IsInterested(pod *v1.Pod) bool
// 抢占阶段
ProcessPreemption(
pod *v1.Pod,
nodeToVictims map[*v1.Node]*extenderv1.Victims,
nodeInfos listers.NodeInfoLister) (map[*v1.Node]*extenderv1.Victims, error)
// 是否支持抢占
SupportsPreemption() bool
// IsIgnorable returns true indicates scheduling should not fail when this extender
// is unavailable. This gives scheduler ability to fail fast and tolerate non-critical extenders as well.
IsIgnorable() bool
}
2.1.2 默认实现
// HTTPExtender implements the algorithm.SchedulerExtender interface.
type HTTPExtender struct {
extenderURL string
preemptVerb string
filterVerb string
prioritizeVerb string
bindVerb string
weight int64 // 对应的权重
client *http.Client // 负责http接口通过
nodeCacheCapable bool // 是否传递node元数据
managedResources sets.String // 当前extender管理的资源
ignorable bool
}
extender的默认是海鲜是同过 HTTPExtender实现,即基于http协议通过json来进行数据传递,其核心数据结构如下
2.2 关键实现机制
2.2.1 远程通信接口
其实通信很简单,通过http协议json序列化方式来进行远程post的提交,并序列化返回的结果
// Helper function to send messages to the extender
func (h *HTTPExtender) send(action string, args interface{}, result interface{}) error {
// 序列化
out, err := json.Marshal(args)
if err != nil {