容器化 RDS:藉助 CSI 擴展 Kubernetes 存儲能力

容器化 RDS:藉助 CSI 擴展 Kubernetes 存儲能力

容器化RDS系列文章:

  • 容器化RDS:計算存儲分離架構下的“Split-Brain”
  • 容器化RDS:計算存儲分離還是本地存儲?
  • 容器化RDS:你需要了解數據是如何被寫"壞"的
  • 容器化RDS:PersistentLocalVolumes和VolumeScheduling

RDS 並不是新生事物,新鮮的是通過容器技術和容器編排技術構建 RDS。對金融客戶而言,他們有強烈擁抱 Docker 和 Kubernetes 的願望,但可用性是嘗試新技術的前提。存儲是持久化應用的關鍵資源,它並不性感,卻是 Monolithic 應用走向 Cloud-Native 架構的關鍵。Kubernetes 存儲子系統已經非常強大,但是還欠缺一些基礎功能,譬如支持 Expand Volume(部分 Storage Vendor 支持)和 SnapShot。本文嘗試從我們的實現分享如下幾個內容:

  • 現有 Kubernetes 存儲插件系統問題
  • Container Storage Interface(CSI)
  • 基於CSI 和分佈式文件系統實現在 MySQL 的 Volume 動態擴展
  • 對 CSI 的展望

名詞說明:

容器化 RDS:藉助 CSI 擴展 Kubernetes 存儲能力

如有遺漏,不吝賜教。可供選的容器編排系統(後面簡稱 CO.)不少,除去 Kubernetes 還有 Mesos、Swarm、Cloud Foundry。以 Kubernetes 為例,其通過 PersistentVolume 抽象對以下存儲的支持:

  • GCEPersistentDisk
  • AWSElasticBlockStore
  • AzureFile
  • AzureDisk
  • FC(Fibre Channel)**
  • FlexVolume
  • Flocker
  • NFS
  • iSCSI
  • RBD(Ceph Block Device)
  • CephFS
  • Cinder(OpenStack block storage)
  • GlusterFS
  • VsphereVolume
  • Quobyte Volumes
  • HostPath
  • VMware Photon
  • Portworx Volumes
  • ScaleIO Volumes
  • StorageOS

不可謂不豐富。Kubernetes 以插件化的方式支持存儲廠商(後面簡稱 SP.)。SP. 通過實現 Kubernetes 存儲插件接口(後面簡稱 Volume Plugin Interface)的方式提供自己的存儲驅動(後面簡稱 Volume Driver)。

  • VolumePlugin
  • PersistentVolumePlugin
  • DeletableVolumePlugin
  • ProvisionableVolumePlugin
  • ExpandableVolumePlugin
  • Provisioner
  • Deleter

以上接口並不需要全部實現,其中 VolumePlugin[1] 是必須實現的接口。

系統架構圖如下:

容器化 RDS:藉助 CSI 擴展 Kubernetes 存儲能力

容器化 RDS:藉助 CSI 擴展 Kubernetes 存儲能力

這種方式為 Kubernetes 提供了豐富的存儲支持列表,但是在具體實現上,SP. Volume Driver 代碼也在 Kubernetes 代碼倉庫(又叫in-tree),它帶來幾個顯著的問題。

從 Kubernetes 的角度看:

基於這些問題和挑戰,CO 廠商提出 Container Storage Interface 用來定義容器存儲標準,它獨立於 Kubernetes Storage SIG,由 Kubernetes、Mesos、Cloud Foundry 三家一起推動。個人理解它有如下2個核心目標:

  • 提供統一的 CO. 和 SP. 都遵循的容器存儲接口。
  • 一旦 SP. 基於 CSI 實現了自身的 Volume Driver,即可在所有支持 CSI 的 CO 中平滑遷移。

Note:Container Storage Interface 定義[2]。

還有一個附帶的好處是,一旦 CO. 和 SP. 都遵循 CSI,就便於將 Volume Driver 解耦到 Kubernetes 的外部(又叫 out-of-tree)。Kubernetes 只用維護 CSI 接口,不用再維護 SP. 的具體實現,維護成本大大降低。

CSI 優化下的架構圖:

容器化 RDS:藉助 CSI 擴展 Kubernetes 存儲能力

容器化 RDS:藉助 CSI 擴展 Kubernetes 存儲能力

可以看到,Kubernetes 和 SP. 從此涇渭分明,但事情並沒有那麼簡單,借用一位大神說的:

The performance improvement does not materialize from the air, it comes with code complexity increase.

和性能一樣,擴展性和解耦也不是憑空出現。上圖可進一步細化成下圖:

容器化 RDS:藉助 CSI 擴展 Kubernetes 存儲能力

明顯的變化有:

  • Controller Plane、Kubelet 不再直接與 Volume Driver 交互,引入 external-provisioner 和 external-attacher 完成該工作;
  • SP. Volume Driver 會由獨立的容器運行;
  • 為了實現 external-provisioner、external-attacher 和 SP. Volume Driver 的交互引入 gRPC 協議(標紅箭頭)。

還有一些其他的變化:

  • 在 Kubernetes 端 引入新的對象:
  • CSIPersistentVolumeSource:該類型 PV 由 CSI Driver 提供
  • VolumeAttachment:同步 Attach 和 Dettach 信息
  • 引入新的名稱:
  • mount/umount:NodePublishVolume/NodeUnpublishVolume
  • attach/dettach:ControllerPublishVolume/ControllerUnpublishVolume

Note:Kubernetes 適配 CSI 設計文檔[3]。

可見,為了達到這個目標,相比原來複雜不少,但收益巨大,Kubernetes 和 SP. 的開發者可以專注於自身的業務。

即便如此,在現有的 CSI 上做擴展有時也在所難免。

基於 CSI 和分佈式文件系統實現在 MySQL 上的 Dynamically Expand Volume

容器化 RDS:藉助 CSI 擴展 Kubernetes 存儲能力

Kubernetes 存儲子系統已經非常強大,但是還欠缺一些基礎功能,譬如支持 Expand Volume (部分 Storage Vendor 支持)和 SnapShot,尤其是 Expand Volume,這是必須的功能,因為隨著業務的變化,容量的增加在所難免,一旦容量接近閾值,若以遷庫的方式擴展存儲容量,成本太高。

但現狀並不樂觀,Kubernetes 1.10.2 使用 CSI 0.2.0,其並不包含 Expand Volume 接口,這意味著即便底層的存儲支持擴容,Kubernetes 也無法使用該功能,所以我們需要做點 hard code 實現該功能:

  • 擴展 CSI Spec
  • 擴展 CSI Plugin
  • 基於 CSI Spec 實現 Storage Driver
  • 演示
  • 其他

擴展 CSI Spec

前面提到,在 CSI 中引入了 gRPC,個人理解在 CSI 的場景有如下3個優點:

  • 基於 protobuf 定義強類型結構,便於閱讀和理解
  • 通過 stub 實現遠程調用,編程邏輯更清晰
  • 支持雙工和流式,提供雙向交互和實時交互

網絡上介紹 gRPC 和 protobuf 的文章很多,這裡不贅述。

通過 gRPC,實現 CSI 各個組件的交互。為支持 expand volume 接口,需要修改 csi.proto,在 CSI 0.2.0 的基礎上添加需要的 rpc,重點如下:

容器化 RDS:藉助 CSI 擴展 Kubernetes 存儲能力

原 csi.proto[4] 和設計文檔[5]。

通過 CSI 提供的編譯功能,用新編譯出來的 csi.pb.go 替換 external-provisioner、external-attacher、csi-driver 和 kubernetes 中現有的 csi.pb.go。

Note:CSI 編譯時默認使用最新版本的 protobuf 第三方包,這可能會導致 csi.pb.go 跟 Kubernetes 中依賴的 protobuf 第三方包不兼容,編譯時需要切換到統一版本。

擴展 CSI Plugin

在現有 CSI Plugin 基礎上,實現接口 ExpandableVolumePlugin:type ExpandableVolumePlugin interface {

VolumePlugin

ExpandVolumeDevice(spec *Spec, newSize resource.Quantity, oldSize resource.Quantity) (resource.Quantity, error)

RequiresFSResize() bool

}仿照 csiMountMgr 的方式調用 CSI Driver 中的 ControllerResizeVolume。

基於 CSI Spec 實現 Storage Driver

  • CSI Driver 實現如下所有接口:
  • CreateVolume
  • DeleteVolume
  • ControllerPublishVolume
  • ControllerUnpublishVolume
  • ValidateVolumeCapabilities
  • ListVolumes
  • GetCapacity
  • ControllerGetCapabilities
  • RequiresFSResize
  • ControllerResizeVolume

這裡涉及到比較複雜的調試和適配工作,還有一些其他的工作:

  • 定義 CSI 對應的 StorageClass,並設置 allowVolumeExpansion 為 true
  • 啟用 Feature Gates:ExpandPersistentVolumes
  • 新增 Admission Control:PersistentVolumeClaimResize
  • ……

演示

容器化 RDS:藉助 CSI 擴展 Kubernetes 存儲能力

通過擴展 Container Storage Interface 0.2.0,我們在Kubernetes 1.10.2 上實現了在線擴容文件系統擴容。對 MySQL 實例製造兩種類型工作負載:

  • 通過鍵值更新和查詢
  • 批量數據加載數據

通過上圖可以觀察到:

  • 讀數一:MySQL QPS 在正常波動範圍內;
  • 讀數二:持續批量加載數據,MySQL 文件系統容量不斷變大;
  • 讀數三:在20分鐘內,在線動態擴容 Volume 和 Filesystem 2 次, 過程高效平滑。

其他

工作到這裡基本結束,要改動的地方不少,客觀上並不簡單。如果沒有 Kubernetes 和 CSI,難度會更大。

通過此方法可以完成對其他 Storage Vendor 的擴展,譬如 FCSan、iSCSI。

容器化 RDS:藉助 CSI 擴展 Kubernetes 存儲能力

目前 CSI 已發展到 0.2.0,0.3.0 也發佈在即。

0.3.0 中呼聲最高的特性是 Snapshot。藉助該功能,可以實現備份和異地容災。但是為了實現該功能,在 Kubernetes 現有的 Control-Plane 上還要添加新的 Controller,客觀上,複雜度會進一步提高。

同時,部分 in-tree Volume Driver 已通過 CSI 遷移到外部,考慮到 Kubernetes 整體的發佈節奏和 API 的穩定性,個人覺得節奏不會太快。

除此之外,CSI 可能還有更多工作要做。以一個高可用的場景為例,當一個 Node 發生故障時,CO 觸發 Unmount->Dettach->Attach->Mount 的流程,配合 Pod 的漂移,藉助 CSI 定義的接口,Unmount、Dettach、Attach、Mount 由SP. 自身現實,但是 Unmount->Dettach->Attach->Mount 的流程還是有 CO 控制,這個流程並不標準,但是對 workload 又至關重要。

容器化 RDS:藉助 CSI 擴展 Kubernetes 存儲能力

又想起中的那句 “No Silver Bullet”。

相關鏈接:

  1. https://github.com/kubernetes/kubernetes/blob/afa68cc28749c09f8655941b111e46d85689daf8/pkg/volume/plugins.go#L95
  2. https://github.com/container-storage-interface/spec/blob/master/spec.md
  3. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/storage/container-storage-interface.md
  4. https://github.com/container-storage-interface/spec/blob/master/csi.proto
  5. https://docs.google.com/document/d/1kVrNwA2f4ite8_9QvCy-JQA_00hxGGMdER3I84dUDqQ/edit?usp=sharing


分享到:


相關文章: