kubelet源碼分析(一)——kubelet啓動流程及pod狀態變化感知和消費流程

目錄

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啓動流程

函數調用圖:

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

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狀態變化感知流程

函數調用圖:

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隊列中

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了。

調用鏈如下圖

syncLoop是處理pod變化的主loop,一旦觀察變換就會同步期望狀態和運行狀態。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章