深入淺出聊聊Kubernetes儲存(一):詳解Kubernetes儲存關鍵概念
近年來一直關注雲端計算領域的人,必定知道Docker和Kubernetes的崛起。如今,世界範圍內的公有云巨頭(谷歌、亞馬遜、微軟、華為雲、阿里雲等等)都在其傳統的公共雲服務之上提供託管的Kubernetes服務。Kubernetes功能強大、擴充套件性高,在許多人看來,它正在成為雲端計算的終極解決方案。
但不得不說的是,儘管Kubernetes建立在谷歌在生產環境執行工作負載的超過15年的經驗之上,它非常複雜,一些設計決策總是讓使用者難以理解。即使對於經驗最豐富的工程師來說,Kubernetes的學習曲線也很陡峭。
就以儲存來舉例。你知道PV和PVC的區別嗎?storage class和provisioner的關係是什麼?VolumeClaimTemplates是什麼?什麼時候該用statefulset?
在本文中,我將嘗試解釋Kubernetes中的一些關鍵概念,以及我對它們的看法。我希望這也會幫助大家更多地瞭解Kubernetes。使用Kubernetes時,有許多設計選擇和警告讓我意想不到。今天我將講講PV、PVC、Storage Class和Provisioner。
Docker中的Volume(卷)
在深入瞭解Kubernetes之前,讓我們先聊聊Docker——畢竟Kubernetes是構建在Docker之上。
Docker因其簡單易用聞名,這也是Docker能如此受歡迎,併成為Kubernetes基礎的原因。Docker容器是無狀態、快速的,它可以被破壞、重建,而不需要付出太多的代價。但是,就像是患了健忘症的人,想要記住有意義的事情是很困難的一樣。無論是資料庫、鍵值儲存、還是一些原始資料,每一個都需要持久化儲存。
在Docker中建立持久化儲存非常簡單。早期版本中,使用者可以使用-v來建立一個新的未定義大小的匿名空卷或者在主機上的目錄中建立繫結掛載。那個時候,雖然可以很容易地通過掛載那些已經被儲存供應商掛載在主機上的目錄,但沒有第三方介面幫助你直接掛載到Docker上。2015年8月,Docker釋出了v1.8版本,正式引入了卷外掛,允許第三方連線它們的儲存解決方案。Docker會呼叫已安裝的卷外掛來建立/刪除/掛載/解除安裝/get/list那些相關卷,而且每個卷都有一個名字,直到今天,卷外掛的框架基本仍保持不變。
持久卷和持久卷宣告
當你想弄清楚如何在Kubernetes中建立持久儲存時,可能會遇到兩個概念:持久卷(Persistent Volume,PV)和持久卷宣告(Persistent Volume Claim,PVC)
它們是什麼?它們中哪個更接近Docker中的卷?
實際上,它們都不像Docker中的卷。除了PV和PVC之外,Kubernetes還有一個Volume的概念,但它與Docker中的概念不同,稍後我們會討論它。
如果你瞭解一些關於PV和PVC資訊,可能會意識到PV就是分配的儲存,而PVC是使用該儲存的請求。如果以前你有云計算或儲存的經驗,那麼你可能會認為PV就是一個儲存池,而PVC是一個從儲存池中分割出來的卷。
不過這都不是PV和PVC真正的意義,在Kubernetes中,一個PV對映到一個PVC,反之亦然,它是一對一的對映。
我已經多次給具有豐富儲存和雲端計算經驗的人解釋過這些問題,他們幾乎都是抓耳撓腮,不明白這是怎麼回事。
而在我第一次遇到這兩個概念的時候,我也沒法理解。
我們在這裡列出PV和PVC的定義
PersistentVolume(PV)是叢集中由管理員配置的一塊儲存。它是叢集中的資源,就和節點是叢集資源一樣。PV是卷外掛比如Volumes,但是它的生命週期獨立於使用PV的任何pod個體。該API物件捕獲實現儲存的詳細資訊,包括NFS、iSCSI或著是雲服務商特定的儲存系統。
PersistentVolumeClaim(PVC)是使用者關於儲存的請求。它類似於一個pod,pod消耗節點資源,而PVC消耗PV資源。Pods可以請求特定級別的資源(CPU和內容),而Claim可以請求特定的大小和訪問模式(例如,可以一次讀/寫或者多次只讀)。
這裡需要留意的是“管理員”以及“使用者”的區別。
簡而言之,Kubernetes將基本儲存單元分為兩個概念。PV是一個儲存器,應該由管理員預先分配,而PVC是使用者對儲存的請求。
也就是說,Kubernetes希望管理員來實現分配各種大小的PV。當用戶建立PVC來請求儲存時,Kubernetes將嘗試用該PVC和預先分配的PV匹配。如果可以找到匹配項,就將PVC繫結到PV,使用者就可以開始使用這片預分配的儲存區。
這種方式和傳統方法不同,傳統方法中管理員並不負責分配每個儲存空間。他們只需要授予使用者訪問某個儲存池的許可權,並且確定該使用者的配額是多少,然後讓使用者從儲存池中分割出所需的儲存部分即可。
不過在Kubernetes的設計中,PV已經從儲存池中分割了出來,等待和PVC進行匹配,因此使用者只能請求到預先分配的固定大小的儲存空間。這就出現了兩種情況:
如果使用者只需要1GiB的卷,而可用的最小PV是1TiB,那麼使用者就必須使用這個1TiB的卷。這樣之後其他使用者就沒法使用到這個卷,而這些使用者可能需求的容量超過了1GiB。這不僅會造成儲存空間的浪費,還會導致由於資源限制無法啟動某些工作負載的情況,而其他的工作負載可能正佔有了不需要的資源。
為了解決第一個問題,管理員要麼需要不斷地和使用者保持通訊,確定使用者需要的儲存大小/效能,要麼就預測好需求,並相應地預先分配PV。
這樣一來就很難強制執行單獨的分配(PV)和使用(PVC)。在實際使用中,我並沒有看到大家講PV和PVC作為他們的設計方式。很可能管理員很快就放棄了建立PV的許可權並把它委託給使用者執行。由於PV和PVC仍然是一對一的繫結,PVC的存在就變得不那麼必要了。
在我看來,至少可以說,使用PV和PVC的示例是不常見的。
Storage Class和Provisioner
可能因為PV和PVC使用起來太麻煩了,在2017年3月,隨著v1.6版本的釋出,Kubernetes引入了動態納管(dynamic provisioning)、Storage Class和Provisioner的概念。動態納管與傳統儲存方法類似。管理員可以使用Storage Class來描述他們提供的儲存“class”。Storage Class可以有不同的容量限制、不同的IOPS或其他Provisioner支援的引數。特定於儲存供應商的Provisioner將與Storage Class一起使用,根據Storage Class物件中設定的引數自動分配PV。此外,Provisioner現在能夠強制執行使用者的報價(quotes)和許可權要求。在這種設計中,管理員已經從預測和分配PV的繁瑣中擺脫出來,這樣的方式更有意義。
另外,你還可以使用Storage Class而無需在Kubernetes中建立Storage Class物件。由於Storage Class也是用於PVC和PV(不必由Provisioner建立)的欄位,因此你可以使用自定義的Storage Class名稱手動建立PV,然後建立一個請求相同Storage Class名稱的PVC。即使儲存類Storage Class物件不存在,Kubernetes也會將PVC繫結到具有相同儲存類名稱的PV上。
dynamic provisioning、Storage Class以及Provisioner對我來說非常有意義,它解決了最初的PV和PVC設計中最大的可用性問題。但與此同時,這些新概念也加劇了Kubernetes儲存的另一個問題,即處理持久儲存的各種方式造成的混亂。在本系列文章的下一篇中,我們將分享Kubernetes中的卷與持久化儲存的相關內容,敬請關注!