目錄
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.1 pkg/kubelet/kubelet.go makePodSourceConfig函數
2.2 pkg/kubelet/config/apiserver.go NewSourceApiServer函數
2.3 pkg/kubelet/config/config.go Merge函數
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
方法最重要的方法有兩個:CreateAndInitKubelet
和startKubelet
,可以理解爲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,一旦觀察變換就會同步期望狀態和運行狀態。