我們前邊的關(guān)于存儲卷的討論,都是在講如何將網(wǎng)絡(luò)存儲設(shè)備掛載到我們的應(yīng)用程序POD中,而在實際項目上,我們必須對集群所提供存儲技術(shù)和類型有深入的理解,才能順利完成將支持類型的volume掛載到容器中,供應(yīng)用程序來持久化數(shù)據(jù)。
舉個例子,如果你使用的是托管的阿里巴巴ACK集群,需要使用OSS存儲類型,那么你就必須定義對應(yīng)的Persistent Volume,當(dāng)我們將應(yīng)用遷移到自己數(shù)據(jù)中心后,就需要定義數(shù)據(jù)中心Kubernetes環(huán)境支持的Persistent Volume對象,因此這種直接定義PV的方式,靈活性太差了。為了能在其他云平臺上使用PV,我們就必須修改YAML文件,以適配新的環(huán)境。
我們一直強調(diào)Kubernetes標(biāo)準(zhǔn)化了應(yīng)用程序的部署,特別是在多個云平臺之間的跨云部署場景,每次都修改PV才能完成部署很明顯有悖于我們介紹的Kubernetes理念。幸運的是,Kubernetes已經(jīng)考慮了這個問題,并且提供了一種更加便利的機制來給POD增加存儲資源。而我們通常把這種機制叫做PV/PVC體系。
理想情況下對于開發(fā)人員而言,部署應(yīng)用程序到Kubernetes集群就不應(yīng)該關(guān)心具體的存儲技術(shù)和細節(jié),就如同Kubernetes將工作節(jié)點進行抽象類型,開發(fā)人員面對的只有POD,而基礎(chǔ)設(shè)施相關(guān)的部分應(yīng)該讓專業(yè)人士來處理,比如集群的運維人員和專業(yè)的devops團隊。
正因為如此,我們在部署應(yīng)用到Kuberntes集群的時候,我們很少直接設(shè)置具體存儲的細節(jié),而是通過一種間接的方式來使用PV提供的存儲能力,如下圖所示,這就把POD和底層具體的存儲系統(tǒng)進行了解耦,POD的定義中不用在包含和具體基礎(chǔ)設(shè)施相關(guān)的配置信息:

很多公司內(nèi)部都會自己搭建NFS文件存儲服務(wù)器,我們來舉個例子,假設(shè)在POD中我們要使用NFS文件服務(wù)來共享數(shù)據(jù),那么在volume的定義中就需要包含NFS文件服務(wù)器的IP地址和要掛載的目錄路徑,如下圖所示:

注:網(wǎng)絡(luò)文件系統(tǒng)(NFS)是文件系統(tǒng)之上的一個網(wǎng)絡(luò)抽象,允許遠程客戶端以和本地文件系統(tǒng)類似的方式來通過網(wǎng)絡(luò)進行數(shù)據(jù)訪問。NFS允許在多個用戶之間共享公共文件系統(tǒng),并提供數(shù)據(jù)集中的優(yōu)勢,來最小化所需的存儲空間。
這樣做的結(jié)果是,我們將POD和具體的集群存儲細節(jié)進行了耦合,從而降低了靈活性。如果我們要將如上這個POD部署到另外一個集群中,那么我們就需要修改NFS文件服務(wù)器的IP地址,修改YAML文件可能會產(chǎn)生錯誤,因此這種方式本質(zhì)上說明POD跨Kubernetes集群部署的靈活性不足。如下圖所示:

由于這個原因,我們需要將環(huán)境相關(guān)的配置信息抽取到另外一個叫PV的對象中,來解耦POD和具體存儲信息,提升POD的兼容性。Kubernetes平臺用PersistentVolume對象來代表集群中可以用來存儲數(shù)據(jù)的volume,如下圖所示,PersistentVolume對象將底層存儲機制的詳細信息從POD的YAML文件中解耦:

由于POD中不再包含基礎(chǔ)設(shè)施相關(guān)的配置信息,兼容性得到了極大的提升。當(dāng)然這些配置信息還是需要的,只是被轉(zhuǎn)移到PV對象上而已。本上上來看,這其實并不是什么新技術(shù)。但是計算機從發(fā)展之初,通過增加一層來解決問題的方法,可以說是屢試不爽,我們應(yīng)該在自己的架構(gòu)設(shè)計中,多多考慮這樣的思想,當(dāng)然需要考慮復(fù)雜性和合理性,并不是說中間層越多越好。
筆者在上篇文章中介紹過使用阿里云OSS存儲卷類型的例子,如果你還有印象的話,應(yīng)該記得我們的配置文件中使用persistentVolumeClaim對象來定義數(shù)據(jù)卷,如下圖所示。在Kubernetes平臺中,通常POD間接的通過PVC映射到PV對象,這就讓PV從POD的生命周期中進一步解耦。

如上圖所示,PersistentVolumeClaim對象表示用戶對存儲資源的需求,由于用戶在使用存儲資源的時候,并不清楚集群中有哪些類型的Volume,因此Kubernetes就引入了這個PVC對象,來簡化使用PV的復(fù)雜度。這樣的話我們只需要在定義POD的時候,使用PVC對象即可,而在PVC對象的定義中,我們需要聲明存儲的需求,比如存儲空間大小,訪問模式等。
當(dāng)POD運行完成退出的時候,會刪除PVC,底層的PV會被釋放,釋放后的PV就可以被其他的PVC使用。接下來我們通過一個實際的例子看看如何定義PCV和PV存儲模式。
比如我們現(xiàn)在已經(jīng)在集群中創(chuàng)建了一個PV對象,指向NFS文件存儲服務(wù)器;有一個PVC對象綁定到PV對象,這樣我們就可以直接在POD的YAML中,數(shù)據(jù)卷定義部分直接指定PVC對象,不用設(shè)置詳細的NFS文件服務(wù)器IP地址等。
如下圖所示,當(dāng)POD被調(diào)度到具體的工作節(jié)點時,Kubernetes負(fù)責(zé)通過PVC引用到PV對象,然后使用PV對象中配置的NFS文件服務(wù)器的信息將對應(yīng)的目錄掛載到容器中。

如上圖所示,POD在創(chuàng)建的時候,會通過PVC引用的PV對象來定位到存儲資源的具體信息,并將指定的目錄掛載到容器實例上。表面看,通過三個對象來掛載存儲資源很明顯比一個要復(fù)雜,但是你有沒有深入思考過Kubernetes為什么要如此設(shè)計?
其實這里最大的好處就是“解耦”,或者叫消除依賴。通過增加PV和PVC這兩個對象,基礎(chǔ)設(shè)施相關(guān)的信息和應(yīng)用的部署YAML解耦了,讓專業(yè)的人,集群管理員來負(fù)責(zé)PV的創(chuàng)建,開發(fā)人員的時間就可以放在更具價值的開發(fā)上,如果要部署,只需要使用PCV來聲明自己的需求就可以了。如下圖所示,我們來看看集群管理員開發(fā)人員是如何配合在一起,各司其職,成功將應(yīng)用部署到Kubernetes集群上:

如上圖所示,開發(fā)人員不用再面對具體底層的存儲資源配置細節(jié),集群管理員統(tǒng)一負(fù)責(zé)配置和管理所有的存儲資源,并且在Kubernetes平臺上通過創(chuàng)建PV對象來提供給應(yīng)用程序使用。當(dāng)開發(fā)人員在部署應(yīng)用的時候,通過創(chuàng)建PVC來聲明具體要使用的資源需求,比如直接指定PV對象的名稱,或者指定請求的存儲空間大小和訪問模式,Kubernetes基于這些信息完成綁定。
接下來我們就可以在POD中定義volume的時候使用PCV,當(dāng)POD被創(chuàng)建的時候,POD中運行的容器實例就可以將存儲設(shè)備attach到工作節(jié)點,并將指定的目錄掛載到容器的文件目錄樹中。大家需要特別注意的是,在PVC/PV模式下,開發(fā)人員不需要了解底層具體的存儲設(shè)備信息,這部分工作屬于專業(yè)人士集群管理員,開發(fā)人員只需要通過PVC來聲明應(yīng)用的存儲資源需求。
進一步講,如果我們的集群是托管實例,那么管理員甚至都不需要自己手動來進行PV的創(chuàng)建和管理,我們可以通過云平臺提供的自動化volume提供機制,在有需要的時候,自動創(chuàng)建PersistentVolume和PersistentVolumeClaim對象,提供給應(yīng)用程序使用。
通過上邊的內(nèi)容,相信讀者對PVC/PV有全面的了解了,接下來我們來通過實際的例子來驗證一下。由于筆者使用的Kubernetes環(huán)境支持的存儲資源非常有限,但是又需要通過具體的例子來說明這些對象如何使用,筆者決定暫緩這部分內(nèi)容到后續(xù)專門介紹如何在阿里云ACK上使用PV/PCV。
好了,今天的內(nèi)容就這么多了,我們下篇文章會介紹云原生模式中一個非常重要的概念,如何讓應(yīng)用無狀態(tài),或者說如何管理應(yīng)用程序的配置信息,敬請期待!