kubelet源码分析(一)之 NewKubeletCommand
以下代码分析基于
kubernetes v1.12.0
版本。本文主要分析 https://github.com/kubernetes/kubernetes/tree/v1.12.0/cmd/kubelet 部分的代码。
本文主要分析 kubernetes/cmd/kubelet
部分,该部分主要涉及kubelet
的参数解析,及初始化和构造相关的依赖组件(主要在kubeDeps
结构体中),并没有kubelet
运行的详细逻辑,该部分位于kubernetes/pkg/kubelet
模块,待后续文章分析。
kubelet
的cmd
代码目录结构如下:
1 | kubelet |
1. Main 函数
kubelet
的入口函数Main
函数,具体代码参考:https://github.com/kubernetes/kubernetes/blob/v1.12.0/cmd/kubelet/kubelet.go。
1 | func main() { |
kubelet代码主要采用了Cobra命令行框架,核心代码如下:
1 | // 初始化命令行 |
2. NewKubeletCommand
NewKubeletCommand
基于参数创建了一个*cobra.Command
对象。其中核心部分代码为参数解析部分和Run
函数。
1 | // NewKubeletCommand creates a *cobra.Command object with default parameters |
2.1. 参数解析
kubelet开启了DisableFlagParsing
参数,没有使用Cobra
框架中的默认参数解析,而是自定义参数解析。
2.1.1. 初始化参数和配置
初始化参数解析,初始化cleanFlagSet
,kubeletFlags
,kubeletConfig
。
1 | cleanFlagSet := pflag.NewFlagSet(componentKubelet, pflag.ContinueOnError) |
2.1.2. 打印帮助信息和版本信息
如果输入非法参数则打印使用帮助信息。
1 | // initial flag parse, since we disable cobra's flag parsing |
遇到help
和version
参数则打印相关内容并退出。
1 | // short-circuit on help |
2.1.3. kubelet config
加载并校验kubelet config
。其中包括校验初始化的kubeletFlags
,并从kubeletFlags
的KubeletConfigFile
参数获取kubelet config
的内容。
1 | // set feature gates from initial flags-based config |
2.1.4. dynamic kubelet config
如果开启使用动态kubelet的配置,则由动态配置文件替换kubelet配置文件。
1 | // use dynamic kubelet config, if enabled |
总结:以上通过对各种特定参数的解析,最终生成kubeletFlags
和kubeletConfig
两个重要的参数对象,用来构造kubeletServer
和其他需求。
2.2. 初始化kubeletServer和kubeletDeps
2.2.1. kubeletServer
1 | // construct a KubeletServer from kubeletFlags and kubeletConfig |
2.2.2. kubeletDeps
1 | // use kubeletServer to construct the default KubeletDeps |
2.2.3. docker shim
如果开启了docker shim参数,则执行RunDockershim
。
1 | // start the experimental docker shim, if enabled |
2.3. AddFlags
1 | // keep cleanFlagSet separate, so Cobra doesn't pollute it with the global flags |
其中:
AddFlags
代码可参考:kubernetes/cmd/kubelet/app/options/options.go#L323AddKubeletConfigFlags
代码可参考:kubernetes/cmd/kubelet/app/options/options.go#L424
2.4. 运行kubelet
运行kubelet并且不退出。由Run函数进入后续的操作。
1 | // run the kubelet |
3. Run
1 | // Run runs the specified KubeletServer with the given Dependencies. This should never exit. |
当运行环境是Windows的时候,初始化操作,但是该操作为空,只是预留。具体执行run(s, kubeDeps, stopCh)
函数。
3.1. 构造kubeDeps
3.1.1. clientConfig
创建clientConfig
,该对象用来创建各种的kubeDeps
属性中包含的client
。
1 | clientConfig, err := createAPIServerClientConfig(s) |
3.1.2. kubeClient
1 | kubeClient, err = clientset.NewForConfig(clientConfig) |
3.1.3. dynamicKubeClient
1 | dynamicKubeClient, err = dynamic.NewForConfig(clientConfig) |
3.1.4. eventClient
1 | // make a separate client for events |
3.1.5. heartbeatClient
1 | // make a separate client for heartbeat with throttling disabled and a timeout attached |
3.1.6. csiClient
1 | // csiClient works with CRDs that support json only |
client赋值
1 | kubeDeps.KubeClient = kubeClient |
3.1.7. CAdvisorInterface
1 | if kubeDeps.CAdvisorInterface == nil { |
3.1.8. ContainerManager
1 | if kubeDeps.ContainerManager == nil { |
3.1.9. oomAdjuster
1 | // TODO(vmarmol): Do this through container config. |
3.2. Health check
1 | if s.HealthzPort > 0 { |
3.3. RunKubelet
通过各种赋值构造了完整的kubeDeps
结构体,最后再执行RunKubelet
转入后续的kubelet执行流程。
1 | if err := RunKubelet(s, kubeDeps, s.RunOnce); err != nil { |
4. RunKubelet
1 | // RunKubelet is responsible for setting up and running a kubelet. It is used in three different applications: |
RunKubelet
函数核心代码为执行了CreateAndInitKubelet
和startKubelet
两个函数的操作,以下对这两个函数进行分析。
4.1. CreateAndInitKubelet
通过传入kubeDeps
调用CreateAndInitKubelet
初始化Kubelet。
1 | k, err := CreateAndInitKubelet(&kubeServer.KubeletConfiguration, |
4.1.1. NewMainKubelet
CreateAndInitKubelet
方法中执行的核心函数是NewMainKubelet
,NewMainKubelet
实例化一个kubelet
对象,该部分的具体代码在kubernetes/pkg/kubelet
中,具体参考:kubernetes/pkg/kubelet/kubelet.go#L325。
1 | func CreateAndInitKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration, |
4.1.2. PodConfig
1 | if kubeDeps.PodConfig == nil { |
NewMainKubelet-->PodConfig-->NewPodConfig-->kubetypes.PodUpdate
。会生成一个podUpdate
的channel来监听pod的变化,该channel会在k.Run(podCfg.Updates())
中作为关键入参。
4.2. startKubelet
1 | // process pods and exit. |
如果设置了只运行一次的参数,则执行k.RunOnce
,否则执行核心函数startKubelet
。具体实现如下:
1 | func startKubelet(k kubelet.Bootstrap, podCfg *config.PodConfig, kubeCfg *kubeletconfiginternal.KubeletConfiguration, kubeDeps *kubelet.Dependencies, enableServer bool) { |
4.2.1. k.Run
1 | // start the kubelet |
通过长驻进程的方式运行k.Run
,不退出,将kubelet的运行逻辑引入kubernetes/pkg/kubelet/kubelet.go部分,kubernetes/pkg/kubelet
部分的运行逻辑待后续文章分析。
5. 总结
kubelet采用Cobra命令行框架和pflag参数解析框架,和apiserver、scheduler、controller-manager形成统一的代码风格。
kubernetes/cmd/kubelet
部分主要对运行参数进行定义和解析,初始化和构造相关的依赖组件(主要在kubeDeps
结构体中),并没有kubelet运行的详细逻辑,该部分位于kubernetes/pkg/kubelet
模块。cmd部分调用流程如下:
Main-->NewKubeletCommand-->Run(kubeletServer, kubeletDeps, stopCh)-->run(s *options.KubeletServer, kubeDeps ..., stopCh ...)--> RunKubelet(s, kubeDeps, s.RunOnce)-->startKubelet-->k.Run(podCfg.Updates())-->pkg/kubelet
。同时
RunKubelet(s, kubeDeps, s.RunOnce)-->CreateAndInitKubelet-->kubelet.NewMainKubelet-->pkg/kubelet
。
参考文章:
赞赏一下