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

使用 CSI 和 Kubernetes 動態擴展卷

Kubernetes 自身擁有一個非常強大的儲存子系統,涵蓋了相當廣泛的使用場景。然而,當計劃使用 Kubernetes 構建產品級關係型資料庫平臺時,我們面臨一個巨大的挑戰:如何解決儲存問題。本文描述瞭如何擴充套件最新的容器儲存介面 0.2.0 並將其與 Kubernetes 整合,並演示了動態擴充套件儲存卷容量的核心方面。

引言

我們關注客戶,尤其是在金融領域,容器編排技術的採用正在大幅增長。

他們期待開源解決方案,以重新設計已經在虛擬化基礎設施或裸機上執行多年的現有單體應用程式。

考慮到可擴充套件性和技術成熟度,Kubernetes 和 Docker 位居榜首。但將單體應用程式遷移到像 Kubernetes 這樣的分散式編排環境具有挑戰性,關係型資料庫對於遷移至關重要。

對於關係型資料庫,我們應該關注儲存。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 的容器編排系統中使用。

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

csi diagram

  • 引入了三個新的外部元件,以解耦 Kubernetes 和儲存提供商邏輯。
  • 藍色箭頭表示呼叫 API Server 的常規方式。
  • 紅色箭頭表示呼叫 Volume Driver 的 gRPC。

更多詳情,請訪問:https://github.com/container-storage-interface/spec/blob/master/spec.md

擴充套件 CSI 和 Kubernetes

為了在 Kubernetes 上啟用擴充套件儲存卷功能,我們應該擴充套件幾個元件,包括 CSI 規範、“in-tree” 儲存卷外掛、外部供應器和外部附加器。

擴充套件 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) {}
}

擴充套件“In-Tree”儲存卷外掛

除了擴充套件 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,該 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。

結論

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