Kubernetes儲存系統介紹及機制實現
一、Kubernetes中儲存的應用場景
在Kubernetes中部署和執行的服務大致分為:
1. 無狀態服務
Kubernetes使用ReplicaSet來保證一個服務的例項數量,如果說某個Pod例項由於某種原因掛掉或崩潰,ReplicaSet會立刻用這個Pod的模版新啟一個Pod來替代它。由於是無狀態的服務,新Pod與舊Pod一模一樣。此外Kubernetes通過Service(一個Service後面可以掛多個Pod)對外提供一個穩定的訪問介面,實現服務的高可用。
2. 普通有狀態服務
和無狀態服務相比,它多了狀態儲存的需求。Kubernetes提供了以Volume和Persistent Volume為基礎的儲存系統,可以實現服務的狀態儲存。
3. 有狀態叢集服務
和普通有狀態服務相比,它多了叢集管理的需求。要執行有狀態叢集服務要解決的問題有兩個,一個是狀態儲存,另一個是叢集管理。Kubernetes為此開發了StatefulSet(以前叫做PetSet),方便有狀態叢集服務在Kubernetes上部署和管理。
簡單來說是通過Init Container來做叢集的初始化工作,用Headless Service來維持叢集成員的穩定關係,用動態儲存供給來方便叢集擴容,最後用StatefulSet來綜合管理整個叢集。
分析以上的服務型別,Kubernetes中對於儲存的使用主要集中在以下幾個方面:
- 服務的基本配置檔案讀取、密碼金鑰管理等;
- 服務的儲存狀態、資料存取等;
- 不同服務或應用程式間共享資料;
二、Kubernetes中幾種常見的儲存系統
目前Kubernetes所支援的Volume Plugins如下表所示,
Kubernetes已經提供非常豐富的Volume和Persistent Volume外掛,大家可以根據自己業務的需要,使用這些外掛給容器提供儲存服務。每一種Plugin的使用方法和注意事項在此不做贅述,請參考 Kubernetes Volume 的官方文件。
容器儲存介面(Container Storage Interface,CSI )是一項跨行業標準倡議,旨在降低雲原生儲存開發工作的門檻,從而進一步確保相容性水平。Kubernetes v1.9已經引入了
如果上述的這些Plugin不滿足業務要求, 你可以通過以下兩種途徑進行二次開發,
- 可以使用FlexVolume實現自己的Volume外掛。此Plugin仍是alpha版本,後向相容性需要考慮。具體方法在此不做贅述,參考 FlexVolume的社群文件。
- 推薦使用CSI。目前還只是alpha版本,使用時需要在
feature-gate
中enable,不推薦在production環境中使用。v1.9已經把 CSI 作為in-tree plugin,把out-off-tree volume外掛的開發從 Kubernetes 中脫離出來,極大地方便了外掛的開發、維護和整合。如何使用CSI,可參考How to Use Kubernetes 1.9.0 with CSI。
三、Kubernetes儲存的設計與基本架構
Kubernete儲存在設計的時候遵循著Kubernetes的一貫哲學,即宣告式(Declarative)架構。同時為了儘可能多地相容各種儲存平臺,Kubernetes以in-tree plugin的形式來對接不同的儲存系統,滿足使用者可以根據自己業務的需要使用這些外掛給容器提供儲存服務。同時相容使用者使用FlexVolume和CSI定製化外掛。相比較於Docker Volume,支援的儲存功能更加豐富和多樣。
Kubernetes中mount 一個PV的基本過程包括:
- 使用者通過API建立一個包含PVC的Pod;
- Scheduler把這個Pod分配到某個節點,比如Node1;
- Node1上的Kubelet開始等待Volume Manager準備device;
- PV controller呼叫相應Volume Plugin(
in-tree
或者out-of-tree
),建立PV,並在系統中與對應的PVC繫結; - Attach/Detach controller或者Volume Manager通過Volume Plugin實現device掛載(Attach);
- Volume Manager等待device掛載完成後,將卷掛載到節點指定目錄(mount), 比如/var/lib/kubelet/pods/xxxxxxxxxxx/volumes/aws-ebs/vol-xxxxxxxxxxxxxxxxx;
- Node1上的Kubelet此時被告知volume已經準備好後,開始啟動Pod,通過volume mapping將PV已經掛載到相應的容器中去。
其實對於Kubernetes中大部分的Volume Plugin來說,mount的過程遵循著如下的規則:
/some/global/mount/path -> /var/lib/kubelet/pods/<pod uid> /volumes/<volume plugin>/<volume name>/ -> container volume
這種方式的好處相當於熱插拔,一旦Pod掛掉,kubelet可以馬上重啟,並快速mount volume,不會出現類似於device busy的情形。
但是對於hostpath
這個Plugin而言,直接就是 /some/global/mount/path -> container volume
。
四、Persistent Volume與Persistent Volume Claim
一個執行中的容器,預設情況下,對檔案系統的寫入,都是發生在其分層檔案系統的可寫層的(Copy-on-Write)。當遷移的應用程式從開發到生產環境時候,開發人員面臨著巨大的挑戰。當容器掛掉、崩潰或執行結束時,任何與之相關的資料都會丟失。為了解決這個問題引發的資料丟失,我們需要將資料儲存持久化,也可以稱為Persistent Volume。
Kubernetes使用兩種資源管理儲存:
- PersistentVolume(簡稱PV):由管理員新增的的一個儲存的描述,是一個全域性資源,包含儲存的型別,儲存的大小和訪問模式等。它的生命週期獨立於Pod,例如當使用它的Pod銷燬時對PV沒有影響。
- PersistentVolumeClaim(簡稱PVC):是Namespace裡的資源,描述對PV的一個請求。請求資訊包含儲存大小,訪問模式等。
Kubernetes中的Volume則是基於Docker進行擴充套件,使用Docker Volume掛載宿主機上的檔案目錄到容器中。
一般來說,Kubernetes中Pod通過如下三種方式來訪問儲存資源。
直接訪問
該種方式移植性較差,可擴充套件能力差,把Volume的基本資訊完全暴露給使用者,有嚴重的安全隱患,同時需要協調不同users對Volume的訪問。
靜態provision
動態provision
StorageClass將說明Volume將由哪種Volume Plugin建立、建立時引數以及從其他功能性/非功能性角度描述的後臺volume的各種引數。一般為storage cluster的一些配置資訊,以及label註釋資訊。
一般來說,PV和PVC的生命週期分為5個階段:
- Provisioning,即PV的建立,可以直接建立PV(靜態方式),也可以使用StorageClass動態建立
- Binding,將PV分配給PVC
- Using,Pod通過PVC使用該Volume
- Releasing,Pod釋放Volume並刪除PVC
- Reclaiming,回收PV,可以保留PV以便下次使用,也可以直接從雲端儲存中刪除
根據這5個階段,Volume的狀態有以下4種:
- Available:可用
- Bound:已經分配給PVC
- Released:PVC解綁但還未執行回收策略
- Failed:發生錯誤
五、v1.9中對儲存做了哪些更改
- 引入了CSI alpha版本的實現,可見第二部分關於CSI的介紹。
- 修復Bug:刪除執行狀態container的PVC這個bug會導致資料丟失。社群的解決辦法是引入一個Finalizer來保護PVC。
簡單來說,這個Fianlizer類似於垃圾回收(GC)裡面的指標計數,當這個使用這個PVC的POD都被刪除(deleted)或處於完成狀態(completed)時,才可以刪除這個PVC。從而避免了刪除正在執行中的container的PVC,從而引發資料丟失。