本文已發布超過一年。較舊的文章可能包含過時的內容。請檢查頁面中的資訊自發布以來是否已變得不正確。

使用 CSI 和 Kubernetes 動態擴展卷

Kubernetes 本身內建非常強大的儲存子系統,涵蓋相當廣泛的使用案例。然而,當計劃使用 Kubernetes 建構產品級關聯式資料庫平台時,我們面臨一個巨大的挑戰:提出儲存方案。本文說明如何擴展最新的容器儲存介面 0.2.0 並與 Kubernetes 整合,並示範動態擴展磁碟區容量的基本面向。

簡介

當我們專注於客戶,尤其是在金融領域的客戶時,容器 Orchestration 技術的採用正在大幅增長。

他們期待使用開放原始碼解決方案來重新設計已在虛擬化基礎架構或裸機上運行多年的現有單體式應用程式。

考量到可擴展性和技術成熟度,Kubernetes 和 Docker 均名列前茅。但將單體式應用程式遷移到像 Kubernetes 這樣的分散式 Orchestration 具有挑戰性,關聯式資料庫對於遷移至關重要。

關於關聯式資料庫,我們應注意儲存。Kubernetes 本身內建非常強大的儲存子系統。它非常有用,並且涵蓋相當廣泛的使用案例。當計劃在生產環境中使用 Kubernetes 運行關聯式資料庫時,我們面臨一個巨大的挑戰:提出儲存方案。仍然有一些基本功能尚未實作。具體而言,動態擴展磁碟區。這聽起來很乏味,但除了建立、刪除、掛載和卸載等動作之外,這是高度需要的。

目前,擴展磁碟區僅適用於以下儲存佈建器

  • gcePersistentDisk
  • awsElasticBlockStore
  • OpenStack Cinder
  • glusterfs
  • rbd

為了啟用此功能,我們應將功能閘道 ExpandPersistentVolumes 設定為 true,並開啟 PersistentVolumeClaimResize 許可外掛程式。一旦啟用 PersistentVolumeClaimResize,Storage Class 的 allowVolumeExpansion 欄位設定為 true 時,便會允許調整大小。

遺憾的是,即使底層儲存供應商具有此功能,也無法透過容器儲存介面 (CSI) 和 Kubernetes 動態擴展磁碟區。

本文將簡要介紹 CSI,然後逐步說明如何在現有的 CSI 和 Kubernetes 上引入新的擴展磁碟區功能。最後,本文將示範如何動態擴展磁碟區容量。

容器儲存介面 (CSI)

為了更了解我們將要做什麼,我們需要知道的第一件事是容器儲存介面是什麼。目前,Kubernetes 內現有的儲存子系統仍然存在一些問題。儲存驅動程式程式碼維護在 Kubernetes 核心儲存庫中,難以測試。但除此之外,Kubernetes 需要授權儲存供應商將程式碼簽入 Kubernetes 核心儲存庫。理想情況下,這應在外部實作。

CSI 旨在定義一個產業標準,使啟用 CSI 的儲存供應商能夠跨支援 CSI 的容器 Orchestration 系統使用。

此圖表描繪了與 CSI 整合的一種高階 Kubernetes 原型

csi diagram

  • 引入了三個新的外部組件,以分離 Kubernetes 和儲存供應商邏輯
  • 藍色箭頭表示呼叫 API 伺服器的傳統方式
  • 紅色箭頭表示呼叫磁碟區驅動程式的 gRPC

如需更多詳細資訊,請造訪:https://github.com/container-storage-interface/spec/blob/master/spec.md

擴展 CSI 和 Kubernetes

為了在 Kubernetes 之上啟用擴展磁碟區的功能,我們應擴展多個組件,包括 CSI 規格、「樹狀結構內」磁碟區外掛程式、external-provisioner 和 external-attacher。

擴展 CSI 規格

在最新的 CSI 0.2.0 中,擴展磁碟區的功能仍未定義。應引入新的 3 個 RPC,包括 RequiresFSResizeControllerResizeVolumeNodeResizeVolume

service Controller {
 rpc CreateVolume (CreateVolumeRequest)
   returns (CreateVolumeResponse) {}
……
 rpc RequiresFSResize (RequiresFSResizeRequest)
   returns (RequiresFSResizeResponse) {}
 rpc ControllerResizeVolume (ControllerResizeVolumeRequest)
   returns (ControllerResizeVolumeResponse) {}
}

service Node {
 rpc NodeStageVolume (NodeStageVolumeRequest)
   returns (NodeStageVolumeResponse) {}
……
 rpc NodeResizeVolume (NodeResizeVolumeRequest)
   returns (NodeResizeVolumeResponse) {}
}

擴展「樹狀結構內」磁碟區外掛程式

除了擴展 CSI 規格外,Kubernetes 內的 csiPlugin 介面也應實作 expandablePlugincsiPlugin 介面將擴展代表 ExpanderControllerPersistentVolumeClaim

type ExpandableVolumePlugin interface {
VolumePlugin
ExpandVolumeDevice(spec Spec, newSize resource.Quantity, oldSize resource.Quantity) (resource.Quantity, error)
RequiresFSResize() bool
}

實作磁碟區驅動程式

最後,為了抽象化實作的複雜性,我們應將個別儲存供應商管理邏輯硬式編碼到以下功能中,這些功能已在 CSI 規格中明確定義

  • CreateVolume
  • DeleteVolume
  • ControllerPublishVolume
  • ControllerUnpublishVolume
  • ValidateVolumeCapabilities
  • ListVolumes
  • GetCapacity
  • ControllerGetCapabilities
  • RequiresFSResize
  • ControllerResizeVolume

示範

讓我們透過具體的用戶案例來示範此功能。

  • 為 CSI 儲存佈建器建立儲存類別
allowVolumeExpansion: true
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: csi-qcfs
parameters:
  csiProvisionerSecretName: orain-test
  csiProvisionerSecretNamespace: default
provisioner: csi-qcfsplugin
reclaimPolicy: Delete
volumeBindingMode: Immediate
  • 在 Kubernetes 叢集中部署 CSI 磁碟區驅動程式,包括儲存佈建器 csi-qcfsplugin

  • 建立 PVC qcfs-pvc,它將由儲存類別 csi-qcfs 動態佈建

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: qcfs-pvc
  namespace: default
....
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 300Gi
  storageClassName: csi-qcfs
  • 建立 MySQL 5.7 執行個體以使用 PVC qcfs-pvc
  • 為了反映完全相同的生產級情境,實際上存在兩種不同類型的工作負載,包括
    • 批次插入以使 MySQL 消耗更多檔案系統容量
    • 激增查詢請求
  • 透過編輯 pvc qcfs-pvc 組態來動態擴展磁碟區容量

Prometheus 和 Grafana 整合讓我們能夠視覺化對應的關鍵指標。

prometheus grafana

我們注意到,中間讀數顯示 MySQL 資料檔案大小在大量插入期間緩慢增加。同時,底部讀數顯示檔案系統在約 20 分鐘內擴展了兩次,從 300 GiB 擴展到 400 GiB,然後擴展到 500 GiB。同時,上方讀數顯示擴展磁碟區的整個過程立即完成,幾乎不會影響 MySQL QPS。

結論

無論應用程式在何種基礎架構上運行,資料庫始終是關鍵資源。擁有更進階的儲存子系統來完全支援資料庫需求至關重要。這將有助於推動更廣泛地採用雲原生技術。