上篇文章(kubelet 架构浅析 )已经介绍过 kubelet 在整个集群架构中的功能以及自身各模块的用途,本篇文章主要介绍 kubelet 的启动流程。
kubernetes 版本: v1.12
kubelet 启动流程
kubelet 代码结构:
1 | ➜ kubernetes git:(release-1.12) ✗ tree cmd/kubelet |
1、kubelet 入口函数 main(cmd/kubelet/kubelet.go)
1 | func main() { |
2、初始化 kubelet 配置(cmd/kubelet/app/server.go)
NewKubeletCommand() 函数主要负责获取配置文件中的参数,校验参数以及为参数设置默认值。
1 | // NewKubeletCommand creates a *cobra.Command object with default parameters |
kubeletDeps 包含 kubelet 运行所必须的配置,是为了实现 dependency injection,其目的是为了把 kubelet 依赖的组件对象作为参数传进来,这样可以控制 kubelet 的行为。主要包括监控功能(cadvisor),cgroup 管理功能(containerManager)等。
NewKubeletCommand() 会调用 Run() 函数,Run() 中主要调用 run() 函数进行一些准备事项。
3、创建和 apiserver 通信的对象(cmd/kubelet/app/server.go)
run() 函数的主要功能:
- 1、创建 kubeClient,evnetClient 用来和 apiserver 通信。创建 heartbeatClient 向 apiserver 上报心跳状态。
- 2、为 kubeDeps 设定一些默认值。
- 3、启动监听 Healthz 端口的 http server,默认端口是 10248。
1 | func run(s *options.KubeletServer, kubeDeps *kubelet.Dependencies, stopCh <-chan struct{}) (err error) { |
kubelet 对 pod 资源的获取方式有三种:第一种是通过文件获得,文件一般放在 /etc/kubernetes/manifests 目录下面;第二种也是通过文件过得,只不过文件是通过 URL 获取的;第三种是通过 watch kube-apiserver 获取。其中前两种模式下,我们称 kubelet 运行在 standalone 模式下,运行在 standalone 模式下的 kubelet 一般用于调试某些功能。
run() 中调用 RunKubelet() 函数进行后续操作。
4、初始化 kubelet 组件内部的模块(cmd/kubelet/app/server.go)
RunKubelet() 主要功能:
- 1、初始化 kubelet 组件中的各个模块,创建出 kubelet 对象。
- 2、启动垃圾回收服务。
1 | func RunKubelet(kubeServer *options.KubeletServer, kubeDeps *kubelet.Dependencies, runOnce bool) error { |
1 | func CreateAndInitKubelet(...){ |
1 | func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,...){ |
RunKubelet 最后会调用 startKubelet() 进行后续的操作。
5、启动 kubelet 内部的模块及服务(cmd/kubelet/app/server.go)
startKubelet() 的主要功能:
- 1、以 goroutine 方式启动 kubelet 中的各个模块。
- 2、启动 kubelet http server。
1 | func startKubelet(k kubelet.Bootstrap, podCfg *config.PodConfig, kubeCfg *kubeletconfiginternal.KubeletConfiguration, kubeDeps *kubelet.Dependencies, enableServer bool) { |
1 | // Run starts the kubelet reacting to config updates |
syncLoop 是 kubelet 的主循环方法,它从不同的管道(FILE,URL, API-SERVER)监听 pod 的变化,并把它们汇聚起来。当有新的变化发生时,它会调用对应的函数,保证 Pod 处于期望的状态。
1 | func (kl *Kubelet) syncLoop(updates <-chan kubetypes.PodUpdate, handler SyncHandler) { |
syncLoopIteration() 方法对多个管道进行遍历,如果 pod 发生变化,则会调用相应的 Handler,在 Handler 中通过调用 dispatchWork 分发任务。
总结
本篇文章主要讲述了 kubelet 组件从加载配置到初始化内部的各个模块再到启动 kubelet 服务的整个流程,上面的时序图能清楚的看到函数之间的调用关系,但是其中每个组件具体的工作方式以及组件之间的交互方式还不得而知,后面会一探究竟。
参考:
kubernetes node components – kubelet
Kubelet 源码分析(一):启动流程分析
kubelet 源码分析:启动流程
kubernetes 的 kubelet 的工作过程
kubelet 内部实现解析