Kubernetes源碼分析之存儲相關

本節全部的代碼基於1.13.4版本。緩存

前言

在kubernetes中,與存儲相關的controller主要由三種:
一、AttachDetachController,簡稱AD Controller,主要處理真實的與volume相關的操做;
二、PersistentVolumeBinderController,其實就是PV Controller,主要負責pv和pvc的生命週期以及狀態的切換;
三、VolumeExpandController,主要負責volume的擴容操做。
oop

PersistentVolumeBinderController

首先追蹤PersistentVolumeBinderController方法,直接進入其Run方法。 插件

很直觀,依賴於三個goroutine:
一、resync;
二、volumeWorker;
三、claimWorker。

resync

進入resync,代碼很簡單,以下: code

resync的主要做用就是不停獲取pvc和pv的信息,傳入到相應的緩存隊列中去。這兩個隊列就是在volumeWorker和claimWorker用到的數據源的信息。

volumeWorker

volumeWorker經過for循環,不停獲取resync緩衝的隊列信息,對pv,即volume作相應的更新操做。主要實現方法updateVolume cdn

進入 updateVolume方法,主要調用 syncVolume方法,這個方法是整個volumeWorker的核心。工做流程以下:
一、若是volume沒有被使用,更新PV的狀態爲 Available
二、volume已經被pvc持有:

  • 若是volume尚未被綁定到pvc上,更新PV狀態爲Available
  • 若是pvc信息爲空,pv的狀態不爲Released且不爲Failed,更新PV狀態爲Released,按照配置的回收策略執行pv的回收(調用reclaimVolume方法);
  • pvc中指定volume的字段和當前volume一致,更新PV狀態爲Bound
  • 若是都不知足,根據狀態判斷是執行回收策略仍是解綁(unbindVolume)操做。

claimWorker

claimWorker的工做流程和volumeWorker相似,核心調用方法爲updateClaim-->syncClaim,主要處理的是pvc生命週期中的各類狀態:Pending、Bound以及Lost。不作過多贅述。
blog

總結

PersistentVolumeBinderController的執行流程很清晰,依賴三個goroutine的協做,分別處理數據的獲取、pv的生命週期的狀態更新和pvc的生命週期的狀態更新。整個邏輯中,沒有對具體的volume作操做,更新的僅僅是kubernetes中定義的pv和pvc資源的信息,說白了就是etcd中的數據。具體幹活的主要仍是AttachDetachController,即AD Controller。接口

AttachDetachController

首先由Run方法進入AD Controller的啓動方法,以下: 生命週期

主要有如下幾個步驟構成啓動步驟:
一、同步各資源的信息,包括Pod、Node、PV、PVC;
二、調用 populateActualStateOfWorld方法獲取Node上Volume的信息;
三、調用 populateDesiredStateOfWorld方法獲取Pod須要對應的Volume信息;
四、 reconciler.Run負責檢查掛載狀態,判斷是否須要掛載或卸載(真正幹活的);
五、 desiredStateOfWorldPopulator.Run同步Pod與Volume的掛載信息,相應信息輸送給 reconciler.Run使用;
六、 pvcWorker控制pvc的流控;
七、相應的信息註冊到 metrics中,供Prometheus採集數據使用。

populateActualStateOfWorld

populateActualStateOfWorld方法主要處理的是Node與Volume之間的關係,主要做用是將Node Volume當前的狀態存入到actualStateOfWorld中。主要方法以下: 隊列

主要步驟以下:
一、獲取全部的Node信息;
二、一一遍歷獲取到的全部的Node,針對Node上已經 attached的Volume,分別置於已經attached狀態和 in-user狀態,將Volume信息添加到 actualStateOfWorld中,並將Node添加到 desiredStateOfWorld中。 actualStateOfWorlddesiredStateOfWorld的數據會在 reconciler.Run使用。

populateDesiredStateOfWorld

populateDesiredStateOfWorld方法主要處理的是Pod與Volume之間的關係,主要做用是將Pod Volume指望的狀態添加到desiredStateOfWorld中去。和populateActualStateOfWorld相似,主要就是針對Volume作標記操做,並將相應的Pod信息緩存到desiredStateOfWorld中或者從desiredStateOfWorld中剔除不匹配的Pod信息。事件

desiredStateOfWorldPopulator.Run

desiredStateOfWorldPopulator.Run方法經過不停的循環,調用findAndAddActivePods方法,經過獲取全部的Pod,判斷是否須要添加到desiredStateOfWorld中去。

reconciler.Run

前面幾步主要的目的是爲了獲取Node Volume和Pod Volume的狀態。其中,Node上的Volume是已經存在的,故稱做爲actualStateOfWorld,而Pod Volume是最終須要生效的資源,故稱之爲desiredStateOfWorldreconciler.Run的做用就是經過不停獲取actualStateOfWorlddesiredStateOfWorld狀態,將Pod與Volume置於相對應的狀態,保證磁盤的最終掛載成功或者卸載成功。主要方法以下:

不停循環調用 reconciliationLoopFunc方法。
首先進入 reconcile方法,這是真正幹活的地方。
reconcile使用了三個大的for循環,處理三類事件:
一、首先剔除須要解綁的Volume,調用 UnmountVolume方法最終調用後臺存儲的解綁接口;
二、將須要Attach或者Mount的volumes調用後臺存儲接口執行Attach或者Mount操做;
三、將須要Detach或者Unmount的devices調用後臺存儲接口執行Detach或者Unmount操做。
其中,Attach操做指的是將Volume在Node上生成卷標,如常見的 /dev/xx等。Mount操做包含了MountDevice和Mount兩部分,其中,MountDevice將生成的卷標掛載成Node的路徑,通常在 /var/lib/kubelet/xx/kubernetes.io/xx下,依賴於不一樣的存儲,Mount最終將MountDevice生成的路徑和Pod須要使用的路徑Mount起來,通常路徑爲 /var/lib/kubelet/pods/xx/volumes/xx
sync方法主要完成Volume的後續操做。若是Volume未被成功綁定,將Volume進行重建或者解綁操做。

ExpandController

Kubernetes在1.8開始支持卷的擴容操做,1.11功能已經處於Beta階段。主要代碼以下:

pvcPopulator.Run監聽PVC的變化,只要PVC中Request字段的Storage值比Status中的大,即表示PVC容量發生了變化,須要擴容。此時,將相應的PV和PVC的信息緩存到 resizeMap中去。以下:
syncResize則是不停獲取 resizeMap中的數據,若是有變化,則調用 ExpandVolume方法生成擴展動做,完成磁盤的擴容和PV、PVC的狀態更新操做。代碼以下:

總結

Kubernetes的存儲主要針對Node、Pod、PV以及PVC四類資源。經過獲取Node上Volume狀態,將其與Pod中的Volume進行綁定,完成卷的加載。最終的綁定或者解綁等操做依賴的是後臺的存儲,包括內置的開源存儲插件或者本身實現的插件(FlexVolume或者CSI)。
在kubelet中,同時存在VolumeManager去管理其節點上的Volume資源信息,基本功能與AD Controller一致。能夠經過kube-controller-manager的--disable-attach-detach-reconcile-sync參數或者kubelet的--enable-controller-attach-detach參數控制是由kube-controller-manager執行volume的attach/detach操做仍是kubelet執行相應的操做。

相關文章
相關標籤/搜索