Kubelet配置源和垃圾回收流程
在上一篇文章中,概括的劃分了kubelet的核心模組,這一篇文章重點來分析一下其中Config和GC在原始碼中是如何實現的。
Config
這部分其實就是kubelet的業務入口,此處所謂的 config
不是指kubelet的配置引數,而是指其業務(也就是pod)配置的意思。形象的說,當你在 /etc/kubernetes/manifests
下放上pod的yaml檔案時,kubelet就通過該模組來掃描到pod配置,然後在kubelet中創建出對應的static pod。同道,當你通過kubectl建立的pod被scheduler排程到該節點時,config模組就會感知到Api-Server上的配置的變動,然後對應的將pod創建出來。
Config關注的源頭有三個:
-
SourceFile
就是啟動kubelet指定的靜態pod目錄
-
SourceURL
覺得就是SourceFile的web版,具體沒有用過
-
SourceApiServer
就是kube-api-server
該部分程式碼的大圖如下
makePodSourceConfig
函式首先呼叫了 NewPodConfig
函式,用於創建出用於podConfig。該函式非常重要,裡面一層層通過 newPodStorage
建立了pod配置讀取到後在記憶體中的儲存,以及對應的merge方法(用於計算pod最終體現出來到底是新增、刪除還是更改或者恢復)。按照kubelet啟動引數的配置,通過對應的三個config的方法( config.NewSourceFile
, config.NewSourceURL
以及 config.NewSourceApiserver
)分別初始化了三種Config關注的源頭。
由於篇幅的原因,圖上沒有畫出,但是卻很重要(有助於理解程式碼)的是:這三個config方法分別運行了goRoutine作為守護程序,用於監聽配置的變化。
當有檢測到配置變化後,三種源頭的實現中都會做一些處理,然後將pod spec及其操作動作寫入到cfg.Channel中。而這個channel剛好就是後續我們在主loop中等到的配置更新的channel。在主loop中,會基於其對pod做的操作,再分別到走不通的路徑去處理pod,最終保障kubelet上的pod是與配置希望的一致。
GarbageCollection(GC)
docker容器的本質是宿主機上的一個程序,為了將容器做差異化的封裝,docker藉助於類似AUFS之類的檔案系統做了很多事情。容器停止執行後,這些檔案系統並不會自動清除,通過 docker ps -a
也能夠看到這些資源(這是為了下次可以快速啟動)。kubelet有一套container gc的方案,專門用於清理宿主機上的非所需容器。
另外,容器映象較耗儲存資源,但是每一臺k8s node的儲存空間都是有限的,kubelet上執行的pod生命週期可能很短,但是每個pod可能都使用不同的映象,這就會導致宿主機上會留下很多不再需要的容器映象,為了將有限的空間騰出來高效利用,kubelet設計了一套image gc的方案。
下圖是這部分程式碼的大致結構:
通過程式碼可以看到,GC機制即將被eviction替代,在kubelet引數中已經有對應的提示資訊。
容器GC
容器GC的業務邏輯主要在 (m *kubeGenericRuntimeManager)GarbageCollect
中,下面是對 m.containerGC.GarbageCollect
註釋的引用,描述了主要的業務邏輯。
GarbageCollect removes dead containers using the specified container gc policy. Note that gc policy is not applied to sandboxes. Sandboxes are only removed when they are not ready and containing no containers.
GarbageCollect consists of the following steps:
gcPolicy.MinAge gcPolicy.MaxPerPodContainer gcPolicy.MaxContainers
上面註釋中提到了三個指標,這裡簡單介紹一下這三個指標對應的引數:
-
minimum-container-ttl-duration (
gcPolicy.MinAge
)容器結束執行多久之後才能被回收;比如: ‘300ms’, ‘10s’ or ‘2h45m
-
maximum-dead-containers-per-container (
gcPolicy.MaxPerPodContainer
)基於容器為單位,指每個容器最大可以儲存多少個已結束的容器,預設是1,負數表示不限制,這些容器會浪費磁碟空間
-
maximum-dead-containers (
gcPolicy.MaxContainers
)基於節點為單位,指節點上最多允許保留多少個已結束的容器,預設是-1,表示不做限制
於是,整個流程串起來就是這樣的情景:
gcPolicy.MinAge gcPolicy.MaxPerPodContainer gcPolicy.MaxContainers gcPolicy.MaxContainers
映象GC
分析完了容器的GC,我們再來聊聊映象GC。kubelet也為映象的GC提供了對應的配置引數,具體如下:
-
minimum-image-ttl-duration
最少這麼久映象都未被使用,才允許清理;比如:’300ms’, ‘10s’ or ‘2h45m’.”
-
image-gc-high-threshold
imageFS磁碟使用率的上限,當達到該值時觸發映象清理。預設值為 90%
-
image-gc-low-threshold
imageFS磁碟使用率的下限,每次清理直到使用率低於這個值或者沒有可以清理的映象了才會停止。預設值為 80%
具體流程比較簡單;
image-gc-high-threshold minimum-image-ttl-duration
值得一提的是,這裡的 image-gc-low-threshold
並非用於每次執行刪除映象時重複的去比較是否滿足條件,而是在在觸發GC的時候,用於計算需要刪除多少bytes即 bytesToFree
。