淺談Kubernetes 持久化存儲管理
?一、引言
Kubernetes從版本1.0以后,引入了兩個新的 API 資源:PersistentVolume 和 PersistentVolumeClaim 實現了對存儲供應的獨立管理。持久卷(PersistentVolume,PV) 是對存儲資源在集群中的抽象;持久卷聲明(PersistentVolumeClaim,PVC)則是用戶對存儲資源的請求。盡管PV和PVC已經實現了對用戶存儲資源請求的管理,但是管理員仍需手動創建各種類型的PV 實現對用戶的存儲供應。為了實現存儲資源的動態供應,Kubernetes從版本1.4以后就引入了存儲類(StorageClass)資源。自1.9版本以后,Kubernetes又引入了容器存儲接口(Container Storage Interface CSI),將存儲驅動代碼從Kubernetes的核心庫中剝離了出來,在Kubernetes和外部存儲間引入了一套標準的存儲管理接口,使得外部存儲可以通過實例化該接口動態為容器提供存儲資源。本文將從上述資源對象入手,對Kubernetes的存儲管理進行簡要說明,并簡述G行在容器存儲管理上的實踐。
二、PV和PVC
1、PV
PV(PersistentVolume) 是集群中存儲資源,一般由管理員創建或者由StorageClass自動創建。他們不同于普通的volume,其生命周期獨立于Pod存在。PV主要包括了存儲能力、訪問模式、存儲類型、回收策略、后端存儲類型等關鍵信息的描述。下文我們來創建一個PV,YAML如下:
針對這個例子,我們來對PV的關鍵屬性進行簡要描述:
- Capacity:描述指定存儲設備的存儲能力,目前僅支持對存儲大小(storage)的設置,未來可能支持IOPS、吞入量等;
- VolumeMode:Kubernetes支持兩種存儲卷模式:Filesystem(文件系統)和Block(塊設備),默認值為Filesytem。當VolumeMode指定為Filesystem時,Kubernetes會在首次掛載時實現對文件系統的初始化;當VolumeMode指定為Block時,則會以原始塊設備的形式掛載給Pod,Pod和Volume之間不會有任何文件系統層;
- AccessModes:描述用戶對存儲資源的訪問權限,需要注意的是一個PV在同一時刻只能以一種訪問模式被掛載,其可選的訪問模式包括:a. ReadWriteOnce(RWO):卷可以被一個節點以讀寫方式掛載,可以被同一節點上的多個Pod訪問;b. ReadOnlyMany(ROX):卷可以被多個節點以只讀方式掛載;c. ReadWriteMany(RWX):卷可以被多個節點以讀寫方式掛載;d. ReadWriteOncePod(RWOP):卷可以被單個Pod 以讀寫方式掛載。此模式必須需要CSI支持以及需要 Kubernetes 1.22 以上版本。
- StorageClassName:指定的存儲類別(StorageClass),只有StorageClassName相同的PV和PVC才能進行綁定。若StorageClassName不進行設置,則會被設置為集群默認的 StorageClass。
2、PVC
PVC 是用戶對存儲資源的申請,主要包括了存儲空間請求、訪問模式、選擇條件和存儲類別等信息的描述。集群根據PVC的描述為其選擇匹配的PV進行綁定。下面我們來創建一個PVC,YAML如下:
針對這個例子,我們來對PVC的關鍵屬性進行簡要描述:
- Resources:描述對存儲資源的請求,例如存儲大小(requests.storage);
- VolumeMode:存儲卷模式,其設置跟PV的設置相同;
- AccessModes:訪問模式,其設置跟PV的設置相同;
- StorageClassName:存儲類別(StorageClass)名稱,當系統設置了StorageClass,則系統會自動為PVC創建相應的PV并進行綁定;
- Selector:選擇器,PVC會根據selector的內容對滿足條件的PV進行篩選,選擇KV匹配的PV進行綁定。
PVC根據上述屬性描述選擇與之匹配的PV進行綁定,需要注意的是,PVC只會在相同的Namespace內選擇PV,同樣的,Pod也只能掛載相同的Namespace的PVC。只有當PVC選擇到合適的PV時,才可以被Pod進行正常掛載,示例如下:
3、PV和PVC的生命周期
PV生命周期的各個階段:
- Available(可用):尚未與任何PVC進行綁定;
- Bound(已綁定):已經綁定到某個PVC;
- Released(已釋放):所綁定的PVC已被刪除,但是資源尚未被集群回收;
- Failed(失敗):卷自動回收操作失敗。
PV和PVC的相互關系如下圖1所示的生命周期:
圖1
Kubernetes提供了兩種存儲資源的供應模式:
靜態模式:集群管理員必須聯系存儲管理員手動來創建新的存儲卷, 然后在 Kubernetes 集群創建 PersistentVolume 對象來表示這些卷,最后用戶創建PVC進行綁定。
動態模式:集群管理員無需手動創建PV卷,通過配置StorageClass來實現對存儲類的管理和資源的動態供應。用戶申請PVC時,指定StorageClassName,對應的StorageClass將會自動完成對應存儲類的存儲卷創建以及Kubernetes集群中PV的創建。若StorageClassName聲明為"", 則說明該PVC禁止使用動態模式。
三、StorageClass和CSI
1、StorageClass
動態供應模式主要基于StorageClass對象實現,集群管理員可以針對不同的存儲類型創建不同的StorageClass,對用戶屏蔽了底層存儲的細節。基于StorageClass的動態存儲供應逐步成為了云平臺的標準存儲配置模式。StorageClass主要包括了存儲提供者以及相關存儲參數的配置。StorageClass一旦創建,則不能被修改,只能刪除重建。示例如下:
示例聲明一個名為standard,由Kubernetes.io/aws-ebs提供的存儲類。
2、CSI
StorageClass提供了存儲動態供應的功能,但是各種后端存儲插件的代碼都必須被放入Kubernetes的主干代碼中以供調用,這種緊耦合的開發模式,導致了巨大的維護成本和諸多問題。因此Kubernetes基于上述考慮,推出了容器存儲接口標準(CSI)。各存儲提供方自行維護自己的存儲插件代碼,只要滿足CSI 標準,即可讓Kubernetes進行調用,無需再耦合在Kubernetes的主干代碼中。CSI 存儲插件的標準實現主要包含兩種組件:
Controller Plugin:Controller主要實現存儲資源和存儲類的管理,一般為單實例部署,可以部署在任意節點上。
Node Plugin:主要實現對Node上存儲卷的管理和操作,包括卷的掛載、卸載等,一般部署為Daemonset,每個Node上運行一個Pod。
四、G行的容器存儲管理實踐
1、背景
G行在云平臺3.0之前已經引入了集中式NAS存儲,在用戶需要申請PV卷時,需要先向存儲管理員提出申請,然后由存儲管理員在存儲端按用戶需求創建一塊存儲卷,再由系統管理員在集群中手動創建PV卷完成資源交付,最后用戶在系統中創建PVC完成資源申請,流程如下圖2所示:
圖2
從上述流程描述可以看出,整個過程中需要大量人為介入,缺乏自動化。Kubernetes本身提供了StorageClass 用于支持資源的動態創建,因此G行考慮在現有基礎上引入CSI存儲插件,實現了自動化存儲交付。并在原有的基礎上,引入了高性能本地存儲和分布式SAN存儲,擴充了存儲資源類型。
2、CSI的部署與實踐
圖3
CSI的部署過程如上圖3所示,過程相對比較復雜,每次Kubernetes集群創建后,若都需要手動部署CSI插件,無疑會增加系統運維的成本。G行在此基礎上引入APP標準化交付框架,將Kubernetes的集群創建操作,以及CSI插件的部署進行了集成,實現了Kubernetes集群的一鍵化創建,標準化交付。當集群創建完成后,相應的CSI插件及StorageClass就已經自動完成了部署,用戶即可直接使用。
集群中已經部署好用戶所需的StorageClass,存儲資源申請只需直接創建PVC即可,示例如下:
剛創建完的PVC的狀態為Pending。
CSI的Controller會Watch kube-apiserver,檢測StorageClass的provisioner為自身的PVC的變化,當感知到PVC的創建后,會自動去存儲端進行存儲卷的創建,存儲卷創建完以后,Controller會自動在集群中創建PV。
圖4
整個過程結束后,可以在集群中看到PV已經被成功創建,PVC的狀態已經變為了Bound。
從圖4上述過程可以看出,用戶申請存儲資源的整個流程中,無需存儲管理員和集群管理員手動干預,即可自動存儲資源交付。
3、使用CSI支持動態擴容
在云平臺3.0中,G行在云平臺3.0中的引入了高性能本地存儲和分布式SAN存儲,這兩類存儲在存儲層基于KVM動態擴容技術可實現對后端存儲卷的動態擴容。在容器平臺中,G行對相應的CSI Controller進行了升級優化,實現了EXPAND_VOLUME的功能,響應用戶的擴容需求。當CSI Controller在Watch到相應的修改后,會調用存儲后端接口對相應的存儲卷和PV卷進行擴容,并對文件系統根據相應設置進行調整。
首先在存儲插件部署時,需要將StorageClass的allowVolumeExpansion字段設置為True,開啟動態擴容,StorageClaas配置示例如下:
對于正在運行中的業務,若用戶有擴容需求,無需卸載其使用的PV卷,直接修改PVC的requests大小,CSI Controller則立即嘗試調用存儲后端接口對相應的存儲卷和PV卷進行擴容,后端存儲在接收到擴容需求后,調用virsh blockresize命令調整存儲卷大小,并將處理結果返回給CSI Controller。CSI Controller確認存儲卷已經擴容后,找到當前存儲卷所掛載的node節點,請求相應的node節點上的CSI Daemonset對擴容卷進行resize,將擴容的容量擴充進文件系統中。至此,用戶的動態擴容需求就完成了。整個擴容流程,用戶無需暫停業務,業務連續性和穩定性得到了保障。
4、多種CSI并行
G行在云平臺3.0中支持了集中式NAS存儲、高性能本地存儲和分布式SAN存儲,并針對這三類存儲類進行了性能測試,針對測試結果梳理了相應的用戶使用場景,部分測試數據如下(測試數據僅供參考):
集中式NAS存儲:作為文件存儲,讀寫性能弱于塊存儲,原生支持文件系統的多節點讀寫,適用于有文件共享需求的用戶使用。
分布式SAN存儲:分布式塊存儲,讀寫性能好。在存儲模式為Filesystem時不支持多節點讀寫,適用于對存儲性能要求較高,無共享存儲需求的用戶使用。
高性能本地存儲:本地塊存儲,讀寫性能好。同樣不支持Filesystem存儲模式下的多節點讀寫,適用于單存儲卷容量300G以下,無共享存儲需求,對存儲性能要求高的用戶使用。
五、總結
Kubernetes通過PV、PVC、StorageClass、CSI標準構建了一套完善的存儲管理機制,G行充分利用Kubernetes資源對象,并針對行內現狀,引入多種存儲類型和對應的CSI存儲插件,實現了多種CSI并行及自動化容器存儲管理。存儲管理員和系統管理員無需再手動創建存儲卷和PV卷,只需在項目創建之初,針對不同的存儲類(StorageClass)給項目分配存儲配額。用戶需要時,可直接創建PVC,CSI 控制器會根據用戶的PVC參數,調用存儲端接口,自動創建存儲卷以及PV卷,實現了用戶的即時申請,即時可用,當用戶有擴容需求時,現有CSI控制器也可支持PV卷的動態擴容,無需管理員手動調整。相比靜態交付管理的模式,集群管理員無需預先配置存儲,既降低了人力成本,又提升了交付效率和業務的連續性。同時,多種存儲類的引入也滿足了不同使用場景下的用戶需求。