深刻淺出聊聊Kubernetes存儲(二):搞定持久化存儲


回 顧node

在本系列文章的上一篇中,咱們講到了PV,PVC,Storage Class以及Provisionergit

簡單回顧一下:github

PV在最一開始是設計成了一個須要管理員預先分配的存儲塊。引入Storage Class和Provisioner以後,用戶能夠動態地供應PV。服務器

PVC是對PV的請求,當和Storage Class一塊兒使用時,它將觸發與相匹配PV的動態供應。spa

PV和PVC老是一一對應的。插件

Provisioner是給用戶提供PV的插件。它能夠把管理員從爲持久化建立工做負載的繁重角色中解脫出來。設計

Storage Class是PV的分類器。相同的Storage Class中的PV能夠共享一些屬性。在大多數狀況下,Storage Class和Provisioner一塊兒使用時,能夠把它看成具備預約義屬性的Provisioner。所以,當用戶請求它時,它可以用這些預約義的屬性動態地提供PV。對象

不過上述這些只是在Kubernetes中使用持久化存儲的其中一種方法而已blog

Volume生命週期

在前一篇文章中,咱們提到Kubernetes中還有一個卷(Volume)的概念。爲了把Volume和持久卷(Persistent Volume)區分開,你們有時會稱它爲In-line Volume或者Ephemeral Volume。

這裏咱們引用Volume的定義:

Kubernetes Volume…有一個顯式的生命週期——這和包含它的pod的生命週期相同。所以,Volume的生命週期比在pod中運行的任何容器都長,而且在容器重啓的時候會保存數據。固然,當Pod終止時,Volume也將終止。更重要的是,Kubernetes支持多種類型的Volume,一個pod中也能夠同時使用任何數量的Volume。
在其核心部分,Volume只是一個目錄,可能其中包含了一些數據,這些數據可由pod中的容器訪問。這些目錄是如何產生的、支持它的介質、以及它的內容都是由所使用的特定volume的類型決定的。在其核心部分,Volume只是一個目錄,可能其中包含了一些數據,這些數據可由pod中的容器訪問。這些目錄是如何產生的、支持它的介質、以及它的內容都是由所使用的特定volume的類型決定的。

Volume一個重要屬性是,它與所屬的pod具備相同的生命週期。若是pod消失了,它也會消失。這與Persistent Volume不一樣,由於Persistent Volume將繼續存在於系統中,直到用戶刪除它。Volume還能夠在同一個pod中的容器間共享數據,不過這不是主要的用例,由於一般狀況下用戶只會在每一個pod中使用一個容器。

所以,這更能夠把Volume看做是pod的屬性而不是一個獨立的對象。正如它的定義所說,Volume表示pod中的目錄,而Volume的類型定義了目錄中的內容。例如,Config Map Volume類型將會在Volume目錄中從API服務器建立配置文件;PVC Volume類型將從目錄中相應的PV裏掛在文件系統等等。實際上,Volume幾乎是在pod中本地使用存儲的惟一方法。

Volume、Persistent Volume和持久卷聲明(Persistent Volume Claim)之間很容易弄混淆。假設有一個數據流,它是這樣PV->PVC->Volume。PV包含了真實數據,綁定到PVC上,最終變成pod中的Volume。

然而,除了PVC,Volume還能夠由Kubernetes直接支持的各類類型的存儲庫支持,從這個意義上來講,Volume的定義也挺使人困惑的。

咱們須要知道的事,咱們已經有了Persistent Volume,它支持不一樣類型的存儲解決方案。咱們還有Provisioner,它支持相似(並不徹底相同)的解決方案。並且咱們還有不一樣類型的Volume。

那麼,它們到底有什麼不一樣呢?如何在它們之間選擇?

持久化數據的多種方式

以AWS EBS爲例。讓咱們來細數Kubernetes中的持久化數據方式吧。

Volume方式

awsElasticBlockStore是一個Volume類型。

你能夠建立一個Pod,定義一個awsElasticBlockStore類型的volume,設置好volumeID,接着使用pod中存在的EBS volume。

該EBS volume在直接和Volume使用前必須已經存在。

PV方式

AWSElasticBlockStore仍是一個PV類型。

因此你能夠建立一個PV,用它來表示EBS volume(假設你有這樣的權限),而後建立一個和它綁定的PVC卷。最後,令PVC做爲volume,而後就能夠在pod中使用它了。

和Volume方法相似,EBS volume在建立PV以前就必須存在。

Provisioner方式

kubernetes.io/aws-ebs是一個Kubernetes中用於EBS的內置Provisioner。

你能夠用Provisioner kubernetes.io/aws-ebs來建立一個Storage Class,經過Storage Class建立PVC。Kubernetes會自動爲你建立相對應的PV。接下來指定PVC爲volume就能夠在pod中使用了。

在本用例中,你不須要在使用使用以前建立EBS,EBS Provisioner會爲你建立的。

第三方方式

上面列出的都是Kubernetes內置選項,若是你不太滿意的話,其實還有一些使用Flexvolume driver格式的第三方EBS實現,它們能夠幫助你和Kubernetes鏈接起來。

若是Flexvolume不適合你,還可使用具有一樣功能的CSI drivers(爲何這麼說?稍後會對此進行詳細介紹)

VolumeClaimTemplate方式

若是你在使用StatefulSet,那麼恭喜你!你如今有額外多了一種使用工做負載中EBS的方式——VolumeClaimTemple。

VolumeClaimTemple是StatefulSet規範屬性,它爲StatefulSet所建立的Pod提供了建立匹配PV和PVC的方式。這些PVC將經過Storage Class建立,這樣當StatefulSet擴展時就能夠自動建立它們。當StatefulSet縮小時,多餘的PV/PVCs會保留在系統中。所以,當StatefulSet再一次擴展時,它們會再次做用於Kubernetes建立的新pods中。稍後咱們會詳細講StatefulSet。

舉個例子說明,假設你用replica 3建立了一個名爲www的StatefulSet,並用它建立了名爲data的VolumeClaimTemplate。Kubernetes會建立3個pods,分別起名www-0、www-一、www-2。Kubernetes還會建立PVC,其中www-data-0用於pod www-0,www-data-1給www-1,www-data-2給www-2。若是你把StatefulSet擴展到5,Kubernetes就會分別建立www-三、www-data-三、www-四、www-data-4。若是接着將StatefulSet降爲1,www-1到www-4全都會刪除,而www-data-1到www-data-4會保留在系統中。所以當你決定再次擴展到5的時候,pod www-1到www-4又回被建立出來,而PVC www-data-1仍然會服務於Pod www-1,www-data-2對應www-2,以此類推。這是由於StatefulSet中pod的身份在是stable的。使用StatefulSet時,名稱和關係都是能夠預測的。

VolumeClaimTemple對於像EBS和Longhorn這樣的塊存儲解決方案很是重要。由於這些解決方案本質上是ReadWriteOnce,你不能在Pod之間共享它們。若是你有不止一個運行了持久化數據的pod,那麼就沒法順利地進行部署。所以,VolumeClaimTemplate的出現爲塊存儲解決方案提供了一種水平擴展Kubernetes工做負載的方式。

如何在Volume、Persistent Volume和Provisioner之間作出選擇

正如你所看到的,如今有了內置的Volume類型、PV類型、Provisioner類型、以及使用Flexvolume和/或CSI的外部插件。讓人比較頭大的是,它們之間提供的功能基本相同,不過也有略微的區別。

我認爲,至少應該有一個準則來肯定如何在它們之間選擇。

可是我並無找到。

因此我翻遍了代碼和文檔,畫出了下面的比較表格,以及對我來講最有意義的準則,從Volume、Persistent Volume和Provisioner幾個方面進行對比。

這裏我只涉及到Kubernetes中in-tree所支持的,除此以外一些官方的out-of-tree的Provisioners:

https://github.com/kubernetes...

能夠看到,Volume、Persistent Volume以及Provisioner在一些細微的地方仍是不同的。

  1. Volume支持大部分的volume插件。

    A.它是鏈接PVC和pod的惟一方法

    B.它也是惟一一個支持Config Map、Secret、Downward API以及Projected的。這些全部都與Kubernetes API服務器密切相關。

    C.它仍是惟一一個支持EmptyDir的,EmptyDir能夠自動給pod分配和清理臨時volume。(注:早在2015年,Clayton Coleman就提出了一個關於支持EmptyDir的問題。這對於須要持久化儲存但只有本地卷可用的工做負載,這很是有用。但是這一觀點並無獲得太多的關注。沒有scheduler的支持,這一目標在當時很難作到。而如今,在2018年,Kubernetes v1.11版本的Local Volume已經加入scheduler和PV的節點親和支持(node affinity support),可是仍然沒有EmptyDir PV。並且Local Volume特性並非我所指望的那樣,由於它並不具有在節點上使用新目錄建立新卷的能力。所以,我編寫了Local Path Provisioner,它利用scheduler和PV節點親和更改,爲工做負載提供動態的Host Path type PV。)

  1. PV支持的插件是Provisioner支持的超集,由於Provisioner須要在工做負載使用它以前建立PV。可是,還有一些PV支持而Provisioner不支持的插件,好比Local Volume(正在進行修改中)。
  1. 還有兩種類型Volume是不支持的。他們是兩個最新的特性:CSI和Local Volume,如今還有一些正在進行的工做,會在以後把它們用於Volume。

在Volume、Persistent Volume和Provisioner之間選擇的準則

那麼用戶到底應該選擇哪一種方式呢?

在我看來,用戶們應該堅持一個原則:

在條件容許的狀況下,選擇Provisioner而不是Persistent Volume,接着再是Volume。

詳細來講:

  1. 對於Config Map、Downward API、Secret或者Projected,請使用Volume,由於PV不支持它們。
  2. 對於EmptyDir,直接使用Volume,或者使用Host Path來代替。
  3. 對於Host Path,一般是直接使用Volume,由於它綁定到一個特定的節點,而且節點之間它是同構的。

a. 若是你想用異構的Host Path Volume,它在Kubernetes v1.11版以後才能使用,由於以前缺乏對PV的節點親和知識,使用v1.11+版本,你可使用個人Local Path Provisioner建立帶有節點親和的Host Path PV:

https://github.com/rancher/lo...

  1. 對於其餘的狀況,除非你須要和現有的卷掛鉤(這種狀況下你應該使用PV),不然就使用Provisioner代替。有些Provisioner並非內置的選項,可是你應該能在此連接(https://github.com/kubernetes...)或者供應商的官方倉庫中找到它們。

這個準則背後的原理很簡單。在Kubernetes內部進行操做時,對象(PV)比屬性(Volume)更容易管理,並且和手動建立PV相比,自動建立PV容易得多(Provisioner)。

不過這裏有一個例外:若是你喜歡在Kubernetes外面進行存儲,那麼最好使用Volume,儘管使用這種方式須要用到另外一組API進行建立/刪除。此外,因爲缺乏VolumeClaimTemplate,會失去使用StatefulSet自動伸縮的能力。我不認爲這是多數Kubernetes用戶會選擇的方式。

爲何作一樣的事會有這麼多選項?

當我開始研究Kubernetes存儲時,首先想到的就是這個問題。因爲缺少一致性和直觀性,Kubernetes存儲看起來就像是過後纔想到的。因而我試圖研究這些設計決策背後的歷史原因,但是在2016以前都毫無收穫。

最後,我傾向於相信這些是因爲一些早期的設計形成的,這多是爲獲取供應商支持的迫切需求,致使安排給Volume比本來更多的責任。在我看來,全部複製了PV的內置volume插件都不該該存在。

在研究歷史的過程當中,我發如今2016初發布的Kubernetes v1.2中,dynamic provisioning就已經成爲了alpha特性。它須要兩個發佈版週期變成beta,在兩個週期實現穩定,這都是很是合理的。

SIG Storage(它推進了Kubernetes存儲開發)還進行了大量的工做,使用Provisioner和CSI將Volume插件從tree中移出來。我認爲這是朝着更加一致、更加精簡的系統邁出了一大步。

可另外一方面,我也不認爲這一大堆Volume類型會消失。這像是和硅谷非官方的格言唱反調:快速行動,打破常規。有時候,快速迭代的項目所遺留下來的設計,修改它們實在是太難了。咱們只能和它們共處,在它們身邊當心工做,不要用錯誤的方式調用它們。

下一步

本系列的下一節中,咱們將討論擴展Kubernetes存儲系統的機制,即Flexvolume和CSI。一個小小的提示:你可能注意到了,我並非Flexvolume的粉絲,並且這不是存儲子系統的問題。

相關文章
相關標籤/搜索