第10章 集群與存儲系統(tǒng)

在云環(huán)境中。存儲資源和計算資源的管理方式往往不同。為了能夠屏蔽底層不同存儲廠商存儲實現(xiàn)的細(xì)節(jié),K8s引入了Persistent Volume Claim(PVC)、Persistent Volume(PV)、Storage Class(SC)等API原語(Promitive),以及抽象出來一套標(biāo)準(zhǔn)的可以與K8s交互的接口(FlexVolume、SI),將具體的存儲實現(xiàn)與K8s自身解耦。

10.1 從應(yīng)用的狀態(tài)談起

在K8s集群中的應(yīng)用大致分為無狀態(tài)應(yīng)用和有狀態(tài)應(yīng)用兩種類型,他們對存儲的需求不同。

10.1.1 無狀態(tài)的應(yīng)用

K8s使用ReplicaSet來保證應(yīng)用Pod實例的在線數(shù)量。如果應(yīng)用的某個實例由于某種原因壞了(例如Pod所在的宿主機(jī)出故障了),ReplicaSet會立刻用相同模板創(chuàng)建并啟動一個新實例來替代它。

由于是無狀態(tài)的應(yīng)用,新實例和舊實例一模一樣,所以新實例能做到對舊實例的無損替代。此外K8s通過負(fù)載均衡Service的方式,對外提供一個穩(wěn)定的訪問接口,實現(xiàn)應(yīng)用的高可用。

10.1.2 有狀態(tài)的應(yīng)用

對于有狀態(tài)的應(yīng)用,K8s引入了StatefulSet。StatefulSet配合PVC和PV,可以將應(yīng)用的狀態(tài)存儲到遠(yuǎn)端。這樣的應(yīng)用Pod在遇到宿主機(jī)等的故障遷移后,通過復(fù)用之前的遠(yuǎn)端存儲,可實現(xiàn)應(yīng)用帶狀態(tài)的遷移。Stateful Set是通過保持其管理的每個Pod的名字的有序性和不變性的方式,建立了Pod名字與該P(yáng)od使用的存儲(通過PVC來描述)的一一對應(yīng)關(guān)系,從而保證了同名的Pod發(fā)布或遷移過程中始終可以使用“同一份”遠(yuǎn)程存儲。

10.2 基本單元:Pod Volume

K8s中最小的調(diào)度單位是Pod,可以認(rèn)為一個Pod是一個具體的微服務(wù)實例,它一般會包含多個容器。這些容器共享根容器Pause的網(wǎng)絡(luò)命名空間。并可共享在Pod中聲明的所有的Volume。

Pod Volume是對DOcker Volume的一種更高層次的抽象,屬于Pod對象的一部分,面向的是應(yīng)用實例Pod,而不是容器粒度。對K8s中Pod Volume可以使用的Volume類型做一下簡單分類。

(1)本地存儲:Emptydir、Hostpath等,是主要使用Pod運(yùn)行的節(jié)點上的本地存儲。

(2)網(wǎng)絡(luò)(分布式)存儲:

?In-tree(內(nèi)置):awsElasticBlockStore、gcePersistentDosk/nfs等。存儲插件的實現(xiàn)代碼是放在K8s代碼倉庫中的。

Out-of-trss(外置):FlexVolume、CSI等網(wǎng)絡(luò)存儲Inline Volume Plugin,存儲插件單獨實現(xiàn),特別是,CSI是Volume擴(kuò)展機(jī)制的核心發(fā)展方向。

(3)Projected Volume:Secret、ConfigMap、DownwardAPI、ServiceAccountToken,將K8s集群中的一些配置信息以Volume的方式掛載到Pod的容器中,即應(yīng)用可以通過POSIX接口來訪問這些對象中的數(shù)據(jù)。

(4)PVC與PV體系:K8s中將存儲資源與計算資源分開管理的核心設(shè)計。

10.3 核心設(shè)計:PVC與PV體系

在K8s中通過引入PVC和PV資源對象的設(shè)計,來解耦Pod和Pod使用的存儲的生命周期管理,而PVC和PV資源對象由一組單獨的K8s Controller來管理。這樣設(shè)計可給以下常見的場景帶來良好的擴(kuò)展性:

宿主機(jī)故障數(shù)據(jù)遷移(如StatefulSet管理的Pod帶遠(yuǎn)程Volume遷移)

多Pod共享一個數(shù)據(jù)Volume(如共享NFS文件系統(tǒng))

Volume Snapshot和在線擴(kuò)容Size等功能的擴(kuò)展。

而PVC和PV之間有什么區(qū)別呢?為什么K8s引入兩個看起來相近的資源對象呢?

主要是為了簡化用戶使用存儲的過程,區(qū)分存儲使用方與存儲服務(wù)提供方的職責(zé)。用戶只需通過PVC聲明自己需要的存儲Size、AccessMode(單Node獨占還是多Node共享?只讀還是讀寫訪問?)等業(yè)務(wù)真正關(guān)系的需求,而不用關(guān)心存儲系統(tǒng)的實現(xiàn)細(xì)節(jié),PV和其對應(yīng)的后端復(fù)雜信息完全可以交由K8s Cluster或Administrator同一維護(hù)和管控。

K8s中通過PVC和PV使用存儲的兩種方式:

(1)預(yù)先聲明PV的靜態(tài)方式:所需存儲類型、大小等預(yù)先定義和分配好,一般來說相應(yīng)的存儲是預(yù)先分配好,但是這種方式不夠靈活。如下圖所示。

以靜態(tài)方式使用存儲

(2)通過SC按需動態(tài)分配方式:SC用于聲明動態(tài)申請的存儲Volume將有哪種Volume Plugin創(chuàng)建、創(chuàng)建時的參數(shù),還可以從其他功能性和非功能性角度進(jìn)行描述。這種方式可按需動態(tài)分配,使用起來比較靈活,如下圖所示。

以動態(tài)方式使用存儲

10.4 與特定存儲系統(tǒng)解耦

10.4.1 Volume Plugin

前面從應(yīng)用的角度分析了K8s為了給在其上運(yùn)行的容器化服務(wù)提供存儲能力所引入的抽象出來的資源對象。接下來看一下K8s與存儲系統(tǒng)的交互機(jī)制,以及其與特定存儲系統(tǒng)的一步步解耦過程。我們對于存儲系統(tǒng)的核心需求有兩個:申請存儲空間并將其最終掛載到應(yīng)用容器中。對用戶來說,只需要創(chuàng)建資源對象(PVC)。而真正替我們實現(xiàn)這兩個核心需求的,是集群中存儲相關(guān)控制器。

結(jié)合下圖介紹一下一個包含PVC的Pod的創(chuàng)建過程,以及各組件的交互細(xì)節(jié)。

集群存儲插件

(1)用戶通過API Server創(chuàng)建包含PVC的Pod對象。

(2)調(diào)度器把這個Pod分配給某個節(jié)點。

(3)Kubelet開始等待Volume Manager準(zhǔn)備好存儲設(shè)備。

(4)PV Controller調(diào)用相應(yīng)Volume Plugin申請存儲并創(chuàng)建PV與PVC綁定。

(5)Attch-Detach Controller或者kubelet的Volume Manager通過Volume Plugin將存儲設(shè)備掛載到節(jié)點上。

(6)Volume Manager 等待存儲設(shè)備掛載完成后,將Volume掛載到Pod可訪問的目錄下。

(7)Kubelet啟動Pod并將存儲掛載到相應(yīng)的容器中。

總的來說就是通過PV Controller監(jiān)控PV、PVC、SC等資源對象,然后調(diào)用相應(yīng)的存儲插件去申請存儲空間,并通過Attch-Detach Controller或Kubelet Volume Manager將相應(yīng)存儲空間掛載到指定節(jié)點上,然后Pod在啟動的過程中將其掛載到容器可訪問的目錄上。

10.4.2 in-tree(內(nèi)置)Volume Plugin

K8s Storagr SIG停止接受in-tree Volume Plugin,并建議所有存儲提供商使用out-of-tree(內(nèi)置)Volume Plugin。目前兩種推薦的實現(xiàn)方式:FlexVolume和容器存儲接口CSI。

10.4.3 out-of-tree(外置)Volume Plugin

FlexVolume把Kubelet對它的調(diào)用轉(zhuǎn)化為對可執(zhí)行程序命令行的調(diào)用,其基本思路就是把自己實現(xiàn)的卷插件程序放到制定的路徑,供Kubelet創(chuàng)建Pod過程中的特定階段調(diào)用,這樣通過二進(jìn)制命令行形式擴(kuò)展存儲插件能夠提供的功能有限,部署不方便。

而CSI通過規(guī)定一組標(biāo)準(zhǔn)的網(wǎng)格Client調(diào)用接口(gPRC接口),讓存儲提供商去提供網(wǎng)絡(luò)服務(wù)端的調(diào)用實現(xiàn),這網(wǎng)存儲系統(tǒng)就完全是外置的服務(wù)進(jìn)程,甚至可以“跑”在容器中,其架構(gòu)如下圖所示。

集群存儲CSI架構(gòu)

10.5 K8s中 CSI管控組件容器化部署

通過CSI接口,K8s和Storage Provider變得涇渭分明,存儲系統(tǒng)的功能開發(fā)從K8s中徹底剝離,并且可以將存儲插件以容器化的方式部署,可借助K8s的能力大大提升存儲插件的易用性和穩(wěn)定性。

下圖的部署方式是官方推薦的方式,與特定存儲相關(guān)的組件(Third Storage Vendor Container)完全可以由普通的容器化應(yīng)用通過K8s來部署,K8s與存儲系統(tǒng)的交互也通過社區(qū)實現(xiàn)的通用組件(external-provisioner、csi-attacher、node-driver-registrar等)實現(xiàn)了標(biāo)準(zhǔn)化,存儲提供方只用實現(xiàn)圖中綠色部分就可以講一個具體的存儲系統(tǒng)對接到K8s中供容器化的應(yīng)用使用。

10.6 基于K8s的存儲

通過一個“跑”在K8s上的社區(qū)項目Rook介紹一下存儲系統(tǒng)如何借助K8s來簡化存儲系統(tǒng)本身的運(yùn)維。Rook是專用于云原生環(huán)境的文件、塊、對象存儲服務(wù),它依賴K8s實現(xiàn)了一個可以自我管理、自我擴(kuò)容和自我修復(fù)的分布式存儲服務(wù)。支持自動部署、啟動、配置、分配、擴(kuò)容、縮容、升級、遷移、災(zāi)難恢復(fù)、監(jiān)控、以及資源管理等功能,并通過FlexVolume卷插件擴(kuò)展K8s的存儲系統(tǒng)。Pod可以掛載Rook管理的塊設(shè)備或者文件系統(tǒng)。

Rook與K8s的交互關(guān)系如下圖所示。

管控組件容器化部署
Rook與K8s的交互關(guān)系

向Rook這種以服務(wù)的方式計生在容器編排系統(tǒng)上,并為編排系統(tǒng)上運(yùn)行的容器化應(yīng)用提供基礎(chǔ)存儲服務(wù)的做法,可大幅降低存儲系統(tǒng)自身的運(yùn)維成本,對以后存儲系統(tǒng)的嚴(yán)謹(jǐn)也是很好的參考對象。

10.7 總結(jié)

K8s通過PVC和PV體系來簡化容器化的應(yīng)用存儲的方式,同時通過CSI來解耦存儲系統(tǒng)和K8s的交互流程并使其標(biāo)準(zhǔn)化。隨著K8s的進(jìn)一步普及,存儲系統(tǒng)借助K8s來簡化自身部署、運(yùn)維,以保證自身穩(wěn)定性,這也是未來趨勢。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容