<aside> ⏰ 本文主要对调度器初始化启动过程进行分析。
</aside>
kube-scheduler
组件有很多可以配置的启动参数,其核心也是通过 cobra 开发的一个 CLI 工具,所以要掌握 kube-scheduler 的启动配置,需要我们对 cobra 有一个基本的了解,kube-scheduler 主要有两种类型的配置参数:
这里我们主要是了解调度器的核心调度框架和算法,所以主要关注第一种参数即可。
kube-scheduler 的启动入口位于 cmd/kube-scheduler/scheduler.go
文件,该文件中就包含一个 main 入口函数:
// cmd/kube-scheduler/scheduler.go
func main() {
rand.Seed(time.Now().UnixNano())
// 初始化 Cobra.Command 对象
command := app.NewSchedulerCommand()
// 将命令行参数进行标准化(_替换成-)
pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
// 初始化日志
logs.InitLogs()
defer logs.FlushLogs()
// 执行命令
if err := command.Execute(); err != nil {
os.Exit(1)
}
}
其中最核心的就是通过 app.NewSchedulerCommand()
或者一个 Cobra 的 Command 对象,然后最下面调用 command.Execute()
函数执行这个命令,所以核心就是 NewSchedulerCommand
函数的实现:
// cmd/kube-scheduler/app/server.go
// Option 配置一个 framework.Registry
type Option func(runtime.Registry) error
// NewSchedulerCommand 使用默认参数和 registryOptions 创建一个 *cobra.Command 对象
func NewSchedulerCommand(registryOptions ...Option) *cobra.Command {
// 获取默认的配置信息
opts, err := options.NewOptions()
if err != nil {
klog.Fatalf("unable to initialize command options: %v", err)
}
cmd := &cobra.Command{
Use: "kube-scheduler",
Long: `......`,
// 真正执行的函数入口
Run: func(cmd *cobra.Command, args []string) {
if err := runCommand(cmd, opts, registryOptions...); err != nil {
fmt.Fprintf(os.Stderr, "%v\\n", err)
os.Exit(1)
}
},
......
}
......
return cmd
}
如果我们熟悉 Cobra 的基本用法的话应该知道当我们执行 Cobra 的命令的时候,实际上真正执行的是 Cobra.Command 对象中的 Run
函数,也就是这里的 runCommand
函数:
// cmd/kube-scheduler/app/server.go
if err := runCommand(cmd, opts, registryOptions...); err != nil {
fmt.Fprintf(os.Stderr, "%v\\n", err)
os.Exit(1)
}
其中有两个非常重要的参数 opts 与 registryOptions,opts 是一个 Options 对象,该参数包含所有的运行 Scheduler 需要的参数:
// cmd/kube-scheduler/app/options/options.go
// Options 拥有所有运行 Scheduler 需要的参数
type Options struct {
// 默认值,如果设置了 ConfigFile 或 InsecureServing 中的值,这些设置将被覆盖
// KubeSchedulerConfiguration 类似与 Deployment 都是k8s的资源对象,这是这个对象是用于配置调度器使用的
ComponentConfig kubeschedulerconfig.KubeSchedulerConfiguration
SecureServing *apiserveroptions.SecureServingOptionsWithLoopback
// 可为 Healthz 和 metrics 配置两个不安全的标志
CombinedInsecureServing *CombinedInsecureServingOptions
Authentication *apiserveroptions.DelegatingAuthenticationOptions
Authorization *apiserveroptions.DelegatingAuthorizationOptions
Metrics *metrics.Options
Logs *logs.Options
Deprecated *DeprecatedOptions
// ConfigFile 指定是调度程序服务的配置文件的位置
ConfigFile string
// WriteConfigTo 将默认配置写入的文件路径
WriteConfigTo string
Master string
}
其中第一个参数 ComponentConfig kubeschedulerconfig.KubeSchedulerConfiguration
是我们需要重点关注的用于配置调度策略相关参数的地方,通过 NewOptions() 来获取默认配置参数:
// cmd/kube-scheduler/app/options/options.go
// NewOptions 返回一个默认的调度器应用 options 参数。
func NewOptions() (*Options, error) {
cfg, err := newDefaultComponentConfig()
if err != nil {
return nil, err
}
......
o := &Options{
ComponentConfig: *cfg,
......
}
......
return o, nil
}
上面是初始化 Options 的函数,这里我们只关心核心的 ComponentConfig
参数,该参数是通过函数 newDefaultComponentConfig()
来生成默认的配置:
// cmd/kube-scheduler/app/options/options.go
func newDefaultComponentConfig() (*kubeschedulerconfig.KubeSchedulerConfiguration, error) {
versionedCfg := kubeschedulerconfigv1beta1.KubeSchedulerConfiguration{}
// 可用于配置是否开启 Debug 相关特性,比如 profiling
versionedCfg.DebuggingConfiguration = *configv1alpha1.NewRecommendedDebuggingConfiguration()
kubeschedulerscheme.Scheme.Default(&versionedCfg)
cfg := kubeschedulerconfig.KubeSchedulerConfiguration{}
if err := kubeschedulerscheme.Scheme.Convert(&versionedCfg, &cfg, nil); err != nil {
return nil, err
}
return &cfg, nil
}