入口函数-main

scheduler的源码主要存放在两个文件夹下:

/cmd/kube-scheduler/,是scheduler的入口函数,文件结构如下:

kube-scheduler
├── app          # 该目录下包含运行scheduler时所需要的配置对象和参数
│   ├── BUILD
│   ├── config           # 包含配置对象及上下文内容
│   │   ├── BUILD
│   │   └── config.go
│   ├── options         # 包含scheduler运行时需要的参数
│   │   ├── BUILD
│   │   ├── configfile.go
│   │   ├── deprecated.go
│   │   ├── deprecated_test.go
│   │   ├── insecure_serving.go
│   │   ├── insecure_serving_test.go
│   │   ├── options.go
│   │   └── options_test.go
│   ├── server.go       # 读取默认配置文件,并初始化
│   └── testing
│       ├── BUILD
│       └── testserver.go
├── BUILD
├── OWNERS
└── scheduler.go     # main入口函数

1. main 入口函数

代码在/cmd/kube-scheduler/scheduler.go

这里使用命令行框架cobra,创建scheduler的命令对象并对命令参数进行校验。 scheduler组件代码通过cobra生成根命令和子命令来执行命令,使用 cmd.Flags()设置命令参数,通过调用 command.Execute()检验命令参数并执行。有关cobra的更多信息,请参阅cobra

核心代码:

1.1 NewSchedulerCommand()

代码在/cmd/kube-scheduler/app/server.go

NewSchedulerCommand用来初始化scheduler配置并创建SchedulerCommand对象

核心代码

1.1.1 NewOptions

代码在/cmd/kube-scheduler/app/options/options.go

NewOptions用来配置SchedulerServer需要的参数和配置,核心参数为KubeSchedulerConfiguration结构体(代码在/pkg/scheduler/apis/config/types.go

NewOptions的代码:

在第3行中的newDefaultComponentConfig()点进去就会发现调用的是KubeSchedulerConfiguration结构体

1.1.2 runCommand

代码在/cmd/kube-scheduler/app/server.go

代码如下:

第10行,errs := opts.Validate()校验标题1.1.1中提到的options参数

代码如下:

第26行,c, err := opts.Config()初始化scheduler的config对象

config的具体代码如下:

其中主要执行以下操作:

  • 第15行:构建kube clients:client、leaderElectionClient、eventClient

  • 第20行:创建event broadcaster

  • 第24行:设置leader election(如果开启),用来对多个scheduler进行选举

  • 第33行:创建informer对象,主要包括NewSharedInformerFactoryNewPodInformer函数

第36行,algorithmprovider.ApplyFeatureGates()提供默认的算法,后面详细介绍

第45行和第46行:

WithCancel()函数返回的ctx是context.Background()的子context,之后在协程中select,如果stopCh可以读取,则调用cancel()函数。这个cancel()函数在WithCancel()中返回,作用是把context所有的children关闭并移除。

WithCancel()函数的代码:

其中:第10行调用cancel()函数,具体代码如下

第48行:

  1. return Run(ctx, cc, registryOptions...)调用了Run函数(启动程序)

  2. 接着此Run函数调用了sched.Run(ctx)(在下一节代码的106行)

  3. sched.Run(ctx)这个函数会不停的在协程中运行schedulerOne,对pod执行一轮一轮的调度,直到接收到stopChannel。与此同时,用ctx.Done()阻塞住run的运行,直到ctx.Done()可以读取,run才会返回。一旦run()结束,调度器也停止运作。

这3个小步骤是scheduler源码中主要函数的调用流程,下面对 Run 函数详细介绍

2. Run

代码在/cmd/kube-scheduler/app/server.go

在scheduler调度逻辑开始之前,Run函数将与scheduler相关的配置先运行起来

具体代码如下:

主要功能如下:

  • 运行event broadcaster、healthz checks、healthz server、metrics server(根据config构建一个metrics server)

  • 创建scheduler结构体

  • 启动所有的informer,并在调度前等待etcd中的资源数据同步到本地的store中

  • 如果 leader election开启,并有多个scheduler,则进行选举,直到选举结束或退出(一般系统默认scheduler:default-scheduler)

  • 运行sched.Run函数,执行scheduler的调度逻辑

核心源码介绍:

2.1 outOfTreeRegistry

第6行,创建Registry(注册表),其中包含所有可用的plugins,并控制这些plugin的启动和初始化。这里的Registry相当于一个注册中心,只有在Registry中注册了的plugins(策略),才能在之后的scheduler调度逻辑中启动并生效。

2.1.1 Registry

代码在/pkg/scheduler/framework/v1alpha1/registry.go

代码如下:

注释讲解很清晰,不再赘述。

2.2 scheduler.New

第22行,创建scheduler结构体,其中包含scheduler调度逻辑执行过程中需要的所有参数和配置。

其中:

  • 第3行,cc.InformerFactory调用的是SharedInformerFactory接口:Shared 指的是在多个 Informer 中共享一个本地 cache。

  • 第4行,cc.PodInformer调用的是PodInformer接口:基于SharedInformer的监听pod,并根据index来管理pod(当事件类型为add时,将其保存到本地缓存store中,并创建索引;当事件类型为delete时,则在本地缓存中删除此对象)

  • 第5行,cc.Recorder调用的是EventRecorder接口:用来record events

  • 第6行,ctx.Done()调用的是Context接口:使用一个 Done channel

  • 从第7行开始到最后,调用的是cc.ComponentConfig中的参数,即是KubeSchedulerConfiguration结构体:用来配置scheduler

2.3 InformerFactory.Start

第80行,启动所有informers,包括PodInformer、InformerFactory,主要涉及到informer,请参阅informer机制

2.4 WaitForCacheSync

第84行,在调度逻辑执行前,需等到所有的caches同步

在这一步,涉及到reflector(反射器)、apiserver、etcd、store等的关系,一并在informer机制中讲解

2.5 sched.Run

第106行,等待cache同步完成后,开始执行调度逻辑。

Run函数的具体代码如下:

代码在/pkg/scheduler/scheduler.go

以上是从入口函数开始,到执行schedulerOne逻辑之前的源码分析,sched.Run的源码分析在下一节。

Last updated

Was this helpful?