在?startKubelet 方法中開(kāi)始運(yùn)行創(chuàng)建好的kubelet奥喻。kubelet可以只運(yùn)行一次婿牍,即RunOnce,然后立即退出谐檀,也可以作為一個(gè)后臺(tái)daemon長(zhǎng)期運(yùn)行抡谐,調(diào)用startKubelet;
if runOnce {
? ? ? ? k.RunOnce(podCfg.Updates())
} else {
????????startKubelet(k, podCfg, kubeCfg, kubeDeps)
}
startKubelet主要啟動(dòng)一個(gè)goroutine桐猬,執(zhí)行k.Run(podCfg.Updates()),其中podCfg.Updates()返回的是kubetypes.PodUpdate channel麦撵,從這個(gè)channel里面我們可以獲取到Pod信息;
運(yùn)行 kubelet
pkg/kubelet/kubelet.go ? -->? Run 方法
在檢測(cè)到配置更新的時(shí)候溃肪,kubelet 會(huì)開(kāi)始執(zhí)行Run方法免胃。
1. 初始化一些不需要容器運(yùn)行時(shí)就可以啟動(dòng)的模塊
setupDataDirs()? ? // 設(shè)置文件系統(tǒng)路徑
os.MkdirAll(ContainerLogsDir, 0755)? ? // 創(chuàng)建容器日志路徑
imageManager.Start()?? ? // 鏡像管理
serverCertificateManager.Start()?? ? // 證書(shū)管理
containerManager.Start(node, kl.GetActivePods, kl.sourcesReady, kl.statusManager, kl.runtimeService)?? ? // 容器管理
oomWatcher.Start(kl.nodeRef)?? ? // 監(jiān)控oom
gpuManager.Start()??? ? // gpu
resourceAnalyzer.Start()??? ? // 資源監(jiān)控
2. 啟動(dòng)?volumeManager
go kl.volumeManager.Run(kl.sourcesReady, wait.NeverStop)
3.?啟動(dòng)kl.syncNodeStatus,主要是每隔kl.nodeStatusUpdateFrequency會(huì)向kube-apiserver更新本節(jié)點(diǎn)的信息惫撰;
go wait.Until(kl.syncNodeStatus, kl.nodeStatusUpdateFrequency, wait.NeverStop)
4.?啟動(dòng)kl.syncNetworkStatus杜秸,每隔30s會(huì)更新networkplugin狀態(tài);
go wait.Until(kl.syncNetworkStatus, 30*time.Second, wait.NeverStop)
5.?啟動(dòng)kl.updateRuntimeUp润绎,每隔5s會(huì)調(diào)用kl.setRuntimeSync撬碟,同步container runtime(即docker或rkt)的信息;
go wait.Until(kl.updateRuntimeUp, 5*time.Second, wait.NeverStop)
6.?啟動(dòng)kl.syncNetworkUtil莉撇,每隔1m會(huì)同步iptables信息呢蛤;
go wait.Until(kl.syncNetworkUtil, 1*time.Minute, wait.NeverStop)
7.?啟動(dòng)podKiller,負(fù)責(zé)殺死不要的Pod棍郎;
go wait.Until(kl.podKiller, 1*time.Second, wait.NeverStop)
8. 檢查dns limits
go wait.Until(func() { kl.dnsConfigurer.CheckLimitsForResolvConf() }, 30*time.Second, wait.NeverStop)
9.?同時(shí)啟動(dòng)了幾個(gè)重要的manager其障,即kl.statusManager.Start、kl.probeManager.Start涂佃、kl.pleg.Start励翼;
kl.statusManager.Start()? ?
kl.probeManager.Start()
kl.pleg.Start()
10.?最后啟動(dòng)kl.syncLoop(updates, kl)蜈敢;
kl.syncLoop(updates, kl)
main Loop
pkg/kubelet/kubelet.go ? -->? syncLoop?方法
創(chuàng)建了兩個(gè)定時(shí)器:?syncTicker?和?housekeepingTicker,即使沒(méi)有需要更新的 pod 配置汽抚,kubelet 也會(huì)定時(shí)去做同步和清理工作抓狭。
syncTicker := time.NewTicker(time.Second)
housekeepingTicker := time.NewTicker(housekeepingPeriod)
如果在每次循環(huán)過(guò)程中出現(xiàn)比較嚴(yán)重的錯(cuò)誤,kubelet 會(huì)記錄到?runtimeState?中造烁,遇到錯(cuò)誤就等待 5 秒中繼續(xù)循環(huán)否过。
創(chuàng)建一個(gè)for循環(huán)不停的執(zhí)行syncLoopIteration,獲取的Pod信息惭蟋;kubelet通過(guò)三種方式獲取Pod信息苗桂,一種是傳統(tǒng)的通過(guò)watch kube-apiserver獲取pod信息,一種是通過(guò)文件獲取告组,最后一種是通過(guò)http獲取煤伟,后兩種模式即 standalone 模式;(注意第二個(gè)參數(shù)變成了?SyncHandler?類型木缝,這是一個(gè) interface便锨,定義了處理不同情況的接口,這個(gè)Handler其實(shí)就是 kl 實(shí)例本身)
kl.syncLoopIteration(updates, handler, syncTicker.C, housekeepingTicker.C, plegCh)
syncLoopIteration
configCh:? 將pods的配置變動(dòng)信息氨肌,根據(jù)變動(dòng)的類型鸿秆,分發(fā)給不同的方法進(jìn)行處理。
plegCh: PLEG 狀態(tài)怎囚,如果 pod 的狀態(tài)發(fā)生改變(因?yàn)槟承┣闆r被殺死卿叽,被暫停等),kubelet 也要做處理
syncCh: 定時(shí)器管道恳守,每次隔一段事件去同步最新保存的 pod 狀態(tài)?
houseKeepingCh: 觸發(fā) Pods 的清理
liveness manager: 同步 Pods 失敗或者有容器死掉了考婴。健康檢查發(fā)現(xiàn)某個(gè) pod 不可用,一般也要對(duì)它進(jìn)行重啟
Pod 信息處理主要由這個(gè)函數(shù)進(jìn)行處理催烘,configCh這個(gè)channel就是 podcfg?的updates沥阱,即Pod信息的來(lái)源;
從 configCh 讀取Pod信息伊群,然后根據(jù)u.Op為ADD考杉、UPDATE、REMOVE舰始、RECONCILE進(jìn)行處理崇棠,分別調(diào)用handler.HandlePodAdditions(u.Pods)、handler.HandlePodUpdates(u.Pods)丸卷、handler.HandlePodDeletions(u.Pods)枕稀、handler.HandlePodReconcile(u.Pods);
op.RESTORE 的時(shí)候,不能將 Pod 標(biāo)記為準(zhǔn)備就緒萎坷。因?yàn)橐坏?zhǔn)備就緒了凹联,那么清理routines就會(huì)開(kāi)始回收資源;
select {
case u, open := <-?configCh:
? ? ? ??switch u.Op {
? ??? ??case kubetypes.ADD:? ? ? ?handler.HandlePodAdditions(u.Pods)
? ? ? ? ?case kubetypes.UPDATE:? ? ? handler.HandlePodUpdates(u.Pods)
? ? ? ? ?case kubetypes.REMOVE:? ? ? ?handler.HandlePodRemoves(u.Pods)
? ? ? ? ?case.kubetypes.RECONCILE:?? ? ? ?handler.HandlePodReconcile(u.Pods)
? ? ? ? ?case kubetypes.DELETE:? ? ? handler.HandlePodUpdates(u.Pods)
? ? ? ? ?case.kubetypes.RESTORE:??? ? ? ?handler.HandlePodAdditions(u.Pods)
? ??? ? }
plegCh?這個(gè)channel 是處理 PLEG 狀態(tài)哆档, 執(zhí)行同步蔽挠,或者清理操作。
select {
case e := <-?plegCh:
? ? ?if isSyncPodWorthy(e) {
? ? ? ? ? ?handler.HandlePodSyncs([]*v1.Pod{pod})
? ? ?}
? ? ?if e.Type == pleg.ContainerDied {
? ? ? ? ? ?kl.cleanUpContainersInPod(e.ID, containerID)
? ? ?}
syncCh 這個(gè)channel?處理同步操作
select {
case <-syncCh:
? ? ? ? ? ?handler.HandlePodSyncs(podsToSync)
liveness manager 同步容器不健康信息虐呻, 如果 Pod 已經(jīng)不存在了象泵,那么直接返回
select {
case update := <-kl.livenessManager.Updates():
? ? ?pod, ok := kl.podManager.GetPodByUID(update.PodUID)
? ? ?if !ok? {
? ? ? ? ? ?break
? ? ?}
? ? ?handler.HandlePodSyncs([]*v1.Pod{pod})
houseKeepingCh??這個(gè)channel?處理清理操作
select {
case <-houseKeepingCh:
? ? ?if kl.sourcesReady.AllReady()??{
? ? ? ? ? ??handler.HandlePodCleanups()
? ? ?}
重新總結(jié)一些kubelet的流程
1. 匯總:kubelet 的主循環(huán)方法寞秃,它從不同的管道(文件斟叼、URL 和 apiserver)監(jiān)聽(tīng)變化,并把它們匯聚起來(lái)春寿,到一個(gè) channel 上面朗涩。
2. 初審:當(dāng)有新的變化發(fā)生時(shí),它會(huì)調(diào)用對(duì)應(yīng)的處理函數(shù)绑改,交給podWorkers處理谢床,保證 pod 處于期望的狀態(tài)。如果 pod 沒(méi)有變化厘线,它也會(huì)定期保證所有的容器和最新的期望狀態(tài)保持一致识腿。
3. 接待:podWorkers 對(duì)每個(gè) Pod 的 workUpdata 事件排隊(duì),并負(fù)責(zé)更新 Cache 中的 Pod 狀態(tài)造壮,再把具體的任務(wù)轉(zhuǎn)給 kubelet 處理 (syncPod 方法)渡讼。
4. 終審:kubelet 對(duì)符合條件的 Pod 進(jìn)一步進(jìn)行審核,例如檢查是否可以在本節(jié)點(diǎn)運(yùn)行耳璧,對(duì)于符合審查的 Pod 做一些準(zhǔn)備工作成箫,譬如目錄創(chuàng)建,PV創(chuàng)建旨枯,Image 獲取蹬昌,處理Mirror Pod等,最后再把工作轉(zhuǎn)給容器那一層攀隔。
5. 落地:任務(wù)到容器層以后皂贩,它負(fù)責(zé)處理Pod的情況,查看沙盒昆汹,是否重啟等明刷。最終再調(diào)用?startContainer 啟動(dòng)容器。