本文分為三大部分。第一部分主要介紹Kubernetes中常用的幾種儲存,及其使用場景和生命週期等等。第二部分試圖介紹一些設計原則和基本架構,並簡要介紹各種儲存plugin的實現機制及持久捲的一些特性,例如訪問樣式、回收策略等等。動態捲供給是一個Kubernetes獨有的功能,這一功能允許按需建立儲存捲,使管理員不必預先建立儲存捲,而是隨使用者需求進行建立。第三部分會介紹一下v1.9中儲存的一些新特性。
在Kubernetes中部署和執行的服務大致分為:
Kubernetes使用ReplicaSet來保證一個服務的實體數量,如果說某個Pod實體由於某種原因掛掉或崩潰,ReplicaSet會立刻用這個Pod的模版新啟一個Pod來替代它。由於是無狀態的服務,新Pod與舊Pod一模一樣。此外Kubernetes透過Service(一個Service後面可以掛多個Pod)對外提供一個穩定的訪問介面,實現服務的高可用。
和無狀態服務相比,它多了狀態儲存的需求。Kubernetes提供了以Volume和Persistent Volume為基礎的儲存系統,可以實現服務的狀態儲存。
和普通有狀態服務相比,它多了叢集管理的需求。要執行有狀態叢集服務要解決的問題有兩個,一個是狀態儲存,另一個是叢集管理。Kubernetes為此開發了StatefulSet(以前叫做PetSet),方便有狀態叢集服務在Kubernetes上部署和管理。
簡單來說是透過Init Container來做叢集的初始化工作,用Headless Service來維持叢集成員的穩定關係,用動態儲存供給來方便叢集擴容,最後用StatefulSet來綜合管理整個叢集。
分析以上的服務型別,Kubernetes中對於儲存的使用主要集中在以下幾個方面:
-
服務的基本配置檔案讀取、密碼金鑰管理等;
-
服務的儲存狀態、資料存取等;
-
不同服務或應用程式間共享資料。
目前Kubernetes所支援的Volume Plugins如下表所示。
Kubernetes已經提供非常豐富的Volume和Persistent Volume外掛,大家可以根據自己業務的需要,使用這些外掛給容器提供儲存服務。每一種Plugin的使用方法和註意事項在此不做贅述,請參考Kubernetes Volume 的官方檔案[1]。
容器儲存介面(Container Storage Interface,CSI[2])是一項跨行業標準倡議,旨在降低雲原生儲存開發工作的門檻,從而進一步確保相容性水平。Kubernetes v1.9已經引入了CSI的一套alpha實現版本,將新分捲外掛的安裝流程簡化至與安裝pod相當,並允許第三方儲存供應商在無需接觸核心Kubernetes程式碼庫的前提下開發自己的解決方案。
如果上述的這些Plugin不滿足業務要求, 你可以透過以下兩種途徑進行二次開發。
-
可以使用FlexVolume實現自己的Volume外掛。此Plugin仍是alpha版本,後向相容性需要考慮。具體方法在此不做贅述,參考FlexVolume的社群檔案[3]。
-
推薦使用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[4]。
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//volumes/// -> 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中的Volume則是基於Docker進行擴充套件,使用Docker Volume掛載宿主機上的檔案目錄到容器中。
一般來說,Kubernetes中Pod透過如下三種方式來訪問儲存資源。
該種方式移植性較差,可擴充套件能力差,把Volume的基本資訊完全暴露給使用者,有嚴重的安全隱患,同時需要協調不同users對Volume的訪問。
StorageClass將說明Volume將由哪種Volume Plugin建立、建立時引數以及從其他功能性/非功能性角度描述的後臺volume的各種引數。一般為storage cluster的一些配置資訊,以及label註釋資訊。
-
Provisioning,即PV的建立,可以直接建立PV(靜態方式),也可以使用StorageClass動態建立
-
Binding,將PV分配給PVC
-
Using,Pod透過PVC使用該Volume
-
Releasing,Pod釋放Volume並刪除PVC
-
Reclaiming,回收PV,可以保留PV以便下次使用,也可以直接從雲儲存中刪除
-
Available:可用
-
Bound:已經分配給PVC
-
Released:PVC解綁但還未執行回收策略
-
Failed:發生錯誤
-
引入了CSI alpha版本的實現,可見第二部分關於CSI的介紹。
-
修複Bug:刪除執行狀態container的PVC
這個bug會導致資料丟失。社群的解決辦法是引入一個Finalizer來保護PVC。
詳細的步驟請參考相關的Proposal[5]及其程式碼實現[6]。
簡單來說,這個Fianlizer類似於垃圾回收(GC)裡面的指標計數,當這個使用這個PVC的POD都被刪除(deleted)或處於完成狀態(completed)時,才可以刪除這個PVC。從而避免了刪除正在執行中的container的PVC,從而引發資料丟失。
Q:Kubernetes和Cloud Foundry有什麼區別,優勢在什麼地方?
A:Cloud Foundry更像是Application PaaS,Kubernetes主要是Container PaaS。CF不會直接把container層暴露給使用者,Kubernetes則不然,你可以直接訪問container。個人覺得kubernetes的部署和使用更簡單,更直接,操作起來也更方便。
Q:請問對於Galera Cluster的叢集儲存如何設計儲存方案,CSI有考慮有狀態儲存的解決方案嗎?
A:對於有狀態服務,請使用StatefulSet來部署你的應用。Volume只是一個儲存的地方。StatefulSet會負責給Pod設定順序等等,保證是有序的,優雅的刪除停止和擴充套件。
Q:有沒有物件儲存,比如Ceph RGW,在Kubernetes叢集中的使用案例,比如使用者透過客戶端上傳、下載PVC中的資料之類的?
A:有試過RGW來儲存資料,但是效能不是很好,速度要慢很多。在Kubernetes叢集中可以使用RGW來儲存一些靜態的檔案,比如配置檔案,Nginx靜態html檔案之類,使用者也可以下載PV中的資料。不建議對RGW中的資料進行頻繁的更改。
A:CSI在kubernetes v1.9才引入。這部分內容比較多,可以去看看CSI檔案[2],以及Kubernetes官方的介紹[7],以及這個feature實現程式碼[8]。
A:需要在kubelet節點上安裝ceph-common這個包,在volume mount的時候,會呼叫相關的命令。基本上沒什麼坑,RBD提供的volume還是很好使的。
A:儲存的效能與Cluster的能力、儲存的型別有很大關係。實測過RBD的IO效能,當然case by case,當時測出來的結果還是很不錯的,相比較與CephFS、GlusterFS。
Q:多個Pod共享一個Nas,是否可行,需要註意什麼?
A:可行,但是需要註意Volume的讀寫許可權,這個可以透過mount時候的PV的access mode進行設定,比如ReadWrite、ReadWriteOnce等等。
Q:CSI和社群孵化的volume provisioner有什麼區別?
A:CSI的主要目的還是為了給容器儲存定義一個統一的介面,方便進行定製化,以及新功能新增。社群孵化的volume provisioner,你指的應該是external-storage這個專案吧,這個專案的主要目的是為了方便對in-tree的那些Plugin進行修改和定製,這樣可以獨立地進行更新。
Q:請問你現在有把MySQL可以放進PV裡面麼?求介紹這方面的經驗。
A:如果只是單節點的MySQL,直接放進PV就好了,跟其它正常服務一樣。對於多節點的MySQL Cluster,在部署的時候就需要註意了,建議部署成StatefulSet,有狀態的服務。之前有試過用Galera Cluster For MySQL來部署叢集,發現效果不是很好,尤其是在隨意啟停Pod的時候,Cluster的沒辦法自組成新的叢集,新節點也無法加入叢集。你可以再次試驗下,確認一下。 後來使用MySQL Cluster CGE,效果很好,Cluster能夠及時回覆並重新組織起來。
-
https://kubernetes.io/docs/concepts/storage/volumes/
-
https://github.com/container-storage-interface
-
https://github.com/kubernetes/community/blob/master/contributors/devel/flexvolume.md
-
https://blog.thecodeteam.com/2017/12/19/use-kubernetes-1-9-0-csi/
-
https://github.com/kubernetes/community/blob/master/contributors/design-proposals/storage/postpone-pvc-deletion-if-used-in-a-pod.md
-
https://github.com/kubernetes/kubernetes/pull/55824
-
http://blog.kubernetes.io/2018/01/introducing-container-storage-interface.html
-
https://github.com/kubernetes/kubernetes/pull/54529
本次培訓包含:Kubernetes核心概念;Kubernetes叢集的安裝配置、運維管理、架構規劃;Kubernetes元件、監控、網路;針對於Kubernetes API介面的二次開發;DevOps基本理念;微服務架構;微服務的容器化等,點選識別下方二維碼加微信好友瞭解具體培訓內容。
長按二維碼向我轉賬
受蘋果公司新規定影響,微信 iOS 版的贊賞功能被關閉,可透過二維碼轉賬支援公眾號。