搜索
您的当前位置:首页正文

kubernetes1.8 kube-scheduler源码阅读

来源:二三娱乐

很长时间没有写文章,一直在啃kubernetes文档,本来立志一定要读完所有的文档。还有它的最佳实践openshift的文档。但目前为止,我并没有读完kubernetes的文档。当前,我们有需求需要客制化kubernetes的调度函数,所以开始研究kube-scheduler的代码。
kube-scheduler的代码的风格和逻辑对于Gophers并不陌生。权威的作者这样评价kubernetes的源码:代码简洁,设计巧妙,程序逻辑分解得恰到好处,每个组件各司其职,从而化繁为简,主体流程清晰直观,犹如行云流水,一气呵成。(虽然v.1.8.1已经和书中v1.3的代码发生了不小的改变。)总之,kubernetes的源码值得反复阅读学习,主要是每个版本代码都不一样,变化一直在进行中。

kubernetes tag v.1.8.1

kube-scheduler的代码路径为:plugin/

入口程序:plugin/cmd/kube-scheduler/scheduler.go main()

1. 创建NewSchedulerServer和启动调度服务;

2. componentconfig.KubeSchedulerConfiguration{}定义了kube-scheduler的参数信息;

启动程序:plugin/cmd/kube-scheduler/app/server.go Run()

1.创建apiserver客户端--通过REST方式访问APIserver提供的API服务,用来watch pod和node,并调用api server bind接口完成node和pod的Bind操作;

2. 创建eventBroadcaster对象--发送event到logging函数,发送event到eventSink,同时EventRecorder记录event source;

3. 创建sharedInformerFactory对象,并创建PodInformer对象,PodInformer用于watch/list non-terminal pods并缓存;

4. 创建schedulerConfigurator对象

5. 创建genericScheduler对象(接口Scheduler) ,genericScheduler对象的创建过程:

    (1)创建schedulerConfigurator对象,它包含ConfigFactory对象(接口Configurator) plugin/cmd/kube-scheduler/app/configurator.go

   (2)调用schedulerConfigurator对象的create()方法创建Scheduler对象;genericScheduler对象是由ConfigFactory对象(Configurator是接口)的createFromProvider()方法创建的plugin/cmd/kube-scheduler/pkg/scheduler/factory/factory.go

    (3)创建Scheduler需要如下Informer参数:nodeInformer、pvInformer、pvcInformer、rcInformer、rsInformer、statefulsetInformer、serviceInformer ;

7. 启动informerFactory.start() ,开始运行Informer,进行缓存;

SharedInformers提供勾子机制,获得特定资源的添加、更新、删除通知。并提供函数更新缓存,启动执行。简而言之kube-scheduler的"informer"负责:watch/list non-terminal pods, 缓存,并从podQueue中获得NextPod,执行调度;

8. 运行调度程序;

9. 创建Leaderelection对象,并启动leaderElector.Run() -- 创建resourcelock对一些资源上锁。同时,值得一提,controller-manager和kube-scheduler两个组件可以配置跟本机的APIServer通信,也可以不是。在高可用部署情况下,controller-manager和kube-scheduler两个组件,存在选举机制,为了保证选举成功,需要奇数节点部署组件,而当前工作组件只有一个,用于更新集群状态,并与其他节点组件同步信息。

调度程序:plugin/pkg/scheduler/scheduler.goRun()

1. 等待缓存更新完成;

2. 运行调度流程;

调度流程:plugin/pkg/scheduler/scheduler.go scheduleOne()

1. 从podQueue缓存中获得一个Pod;

2. 获得一个suggestedHost,如果获得失败将调用抢占逻辑sched.preempt(),记录算法延迟的度量metrics.SchedulingAlgorithmLatency;--获得suggestedHost是同步操作;

3. Pod将标注为assumedPod;此时Pod并没有被成功调度;

4. 绑定(bind) Pod到suggestedHost,记录调度延迟的度量metrics.E2eSchedulingLatency;--绑定操作是异步操作;

调度逻辑:plugin/pkg/scheduler/scheduler.go Schedule()

1. 根据调度策略算法确定一个suggestedHost;

调度算法函数:

1. 接口类plugin/pkg/scheduler/algorithm/scheduler_interface.go, 默认使用plugin/pkg/scheduler/core/generic_scheduler.go

3. FitPredicates:k8s.io/kubernetes/plugin/pkg/scheduler/algorithm/predicates

4. PrioritiesFunc:k8s.io/kubernetes/plugin/pkg/scheduler/algorithm/priorities

绑定逻辑:plugin/pkg/scheduler/scheduler.go bind()

1. 绑定接口Binder plugin/pkg/scheduler/scheduler.go

2. 更新cache中assumedPod为expired SchedulerCache.FinishBinding(),接口/实现: plugin/pkg/scheduler/schedulercache/interface.go;plugin/pkg/scheduler/schedulercache/cache.go;

3. 记录绑定延迟的度量metrics.BindingLatency;

4. 记录绑定事件;

阅读代码的建议:

1. 读文档,k8s的文档写得非常好,如果文档没有提及的,读代码;
2. 要带着问题探索性的阅读代码,比如:error handling是如何处理的?如果pod没有被正确的调度会发生什么?

调度的性能:

Top