目录

1、kubelet启动流程

1.1 cmd/kubelet/app/server.go  Run方法

1.2 cmd/kubelet/app/server.go  run方法

1.3 cmd/kubelet/app/server.go  RunKubelet方法

1.4 cmd/kubelet/app/server.go  CreateAndInitKubelet方法

1.5 cmd/kubelet/app/server.go  startKubelet方法

2、pod状态变化感知流程

2.1 pkg/kubelet/kubelet.go makePodSourceConfig函数

2.2 pkg/kubelet/config/apiserver.go NewSourceApiServer函数

2.3 pkg/kubelet/config/config.go Merge函数

3、pod消费流程

1、kubelet启动流程

函数调用图:

pod 上直接开nodeport pod启动流程_Pod

1.1 cmd/kubelet/app/server.go  Run方法

pod 上直接开nodeport pod启动流程_Pod_02

initForOS通过对操作系统的判断,如果是windows系统需要做一些预先的特殊处理;

run方法即通过传入的kubeDeps参数开始执行启动操作。

1.2 cmd/kubelet/app/server.go  run方法

进入run方法,开始主要执行对参数的再一次验证,以及新的结构体的初始化。后续开始构建一些重要的客户端,包括eventClient主要处理事件的上报,与apiserver打交道;heartbeatClient主要处理心跳操作,与之后的PLEG相关;csiClient主要与CSI接口相关。配置完成之后,最终进入RunKubelet方法。

1.3 cmd/kubelet/app/server.go  RunKubelet方法

RunKubelet方法最重要的方法有两个:CreateAndInitKubeletstartKubelet,可以理解为CreateAndInitKubelet为参数的配置,startKubelet为最终的启动。

1.4 cmd/kubelet/app/server.go  CreateAndInitKubelet方法

CreateAndInitKubelet方法通过调用NewMainKubelet返回Kubelet结构体。在NewMainKubelet中,主要的配置有:
1、PodConfig。通过makePodSourceConfig可以发现kubelet获取Pod的来源有以下途径:静态Pod、静态Pod的URL地址以及kube-apiserver;
2、容器与镜像的GC参数。
3、驱逐Pod策略。
最终通过参数填充Kubelet结构体,完成kubelet结构体参数的最终配置。

1.5 cmd/kubelet/app/server.go  startKubelet方法

startKubelet方法内部调用了最终的Run方法

可以看到,在该方法内,完成的就是最终的kubelet的任务,通过多个goroutine完成。包括以下系列:
1、volumeManager,volume相关管理;
2、syncNodeStatus,定时同步Node状态;
3、updateRuntimeUp,定时更新Runtime状态;
4、syncNetworkUtil,定时同步网络状态;
5、podKiller,定时清理死亡的pod;
6、statusManager,pod状态管理;
7、probeManager,pod探针管理;
8、启动PLEG, 即PodLifecycleEventGenerator,用来记录Pod生命周期中对应的各种事件。
9、syncLoop,最重要的主进程,不停监听外部数据的变化执行pod的相应操作。
至此,kubelet启动过程完成。启动主要完成的任务就是参数的配置和多个任务的启动,通过构造一个循环进程不停监听外部事件的变化,执行对应的pod处理工作,这也就是kubelet所需要负责的任务。

2、pod状态变化感知流程

函数调用图:

pod 上直接开nodeport pod启动流程_启动流程_03

2.1 pkg/kubelet/kubelet.go makePodSourceConfig函数

makePodSourceConfig中多处调用了cfg.Channel,可以发现传入了三类source(file、http、api),也就是表示pod的变更来自于这三类source。

cfg.Channel(kubetypes.FileSource)
cfg.Channel(kubetypes.HTTPSource)
cfg.Channel(kubetypes.ApiserverSource)

只看apiserver这类源相关的代码就好了,道理都是一样的。

调用cfg.channel生成updatechannel,将updatechannel作为参数传给NewSourceApiServer函数,NewSourceApiServer内部将listwatch发现的pods变化写入updatechannel队列中

pod 上直接开nodeport pod启动流程_启动流程_04

2.2 pkg/kubelet/config/apiserver.go NewSourceApiServer函数

// NewSourceApiserver creates a config source that watches and pulls from the apiserver.
func NewSourceApiserver(c clientset.Interface, nodeName types.NodeName, updates chan<- interface{}) {
	lw := cache.NewListWatchFromClient(c.CoreV1().RESTClient(), "pods", metav1.NamespaceAll, fields.OneTermEqualSelector(api.PodHostField, string(nodeName)))
	newSourceApiserverFromLW(lw, updates)
}

可以发现实际上kubelet创建了一个listwatch去watch所有namespace的、绑定到本node上的pod。将listwatch发现的pods变化写入updatechannel队列中

2.3 pkg/kubelet/config/config.go Merge函数

看注释可以了解到:

  • pod的变化有多个来源
  • 最终会将变化push到update channel中

稍微浏览下代码即可发现:merge()将入参的change解析分类,然后又push到podStorage的updates中。

3、pod消费流程

makePodSourceConfig的返回类型PodConfig包含updates channel,

赋值给了kubeDeps.PodConfig,我们只要找到谁消费了kubeDeps.PodConfig就能知道pod的变化最终在哪里消费了。

kubeDeps.PodConfig, err = makePodSourceConfig(kubeCfg, kubeDeps, nodeName, bootstrapCheckpointPath)

根据kubeDeps.PodConfig的调用关系(使用IDE查看谁调用了PodConfig),发现kubeDeps.PodConfig是在RunKubelet中被传给了startKubelet,然后一路被传到pkg/kubelet/kubelet.go路径下的syncLoop了。

pod 上直接开nodeport pod启动流程_pod 上直接开nodeport_05

pod 上直接开nodeport pod启动流程_函数调用_06

pod 上直接开nodeport pod启动流程_Pod_07

pod 上直接开nodeport pod启动流程_pod 上直接开nodeport_08

调用链如下图

pod 上直接开nodeport pod启动流程_函数调用_09

syncLoop是处理pod变化的主loop,一旦观察变换就会同步期望状态和运行状态。