Kubernetes 儲存的磁碟區插件:從 Flexvolume 到 CSI

Kubernetes 儲存的磁碟區插件:從 Flexvolume 到 CSI

當 Kubernetes 還是 v1.0.0 時,就有捲插件了。 它們需要將系統連接到 Kubernetes 以儲存持久(永久)容器資料。 他們的數量很少,最早的儲存提供者包括 GCE PD、Ceph、AWS EBS 等。

這些插件與 Kubernetes 一起提供,這就是它們得名的原因 - in-tree。 然而,對於許多人來說,現有的此類插件集是不夠的。 工匠們使用補丁為 Kubernetes 核心添加簡單的插件,之後他們組裝了自己的 Kubernetes 並將其安裝在自己的伺服器上。 但隨著時間的推移,Kubernetes 開發人員意識到 問題無法解決。 人們需要 釣魚竿。 在 Kubernetes v1.2.0 的發布中它出現了...

Flexvolume 外掛:最小釣竿

Kubernetes 開發人員創建了 FlexVolume 插件,它是一個變數和方法的邏輯框架,用於與第三方開發人員實現的 Flexvolume 驅動程式一起使用。

讓我們停下來仔細看看 FlexVolume 驅動程式是什麼。 這是一定的 執行檔 (二進位檔案、Python 腳本、Bash 腳本等),執行時將命令列參數作為輸入,並傳回一條包含 JSON 格式的預先已知欄位的訊息。 依照約定,第一個命令列參數總是方法,其餘參數是其參數。

Kubernetes 儲存的磁碟區插件:從 Flexvolume 到 CSI
OpenShift 中 CIFS 共享的連結圖。 Flexvolume 驅動程式 - 位於中心

最小方法集 看起來像這樣:

flexvolume_driver mount # отвечает за присоединение тома к pod'у
# Формат возвращаемого сообщения:
{
  "status": "Success"/"Failure"/"Not supported",
  "message": "По какой причине был возвращен именно такой статус",
}

flexvolume_driver unmount # отвечает за отсоединение тома от pod'а
# Формат возвращаемого сообщения:
{
  "status": "Success"/"Failure"/"Not supported",
  "message": "По какой причине был возвращен именно такой статус",
}

flexvolume_driver init # отвечает за инициализацию плагина
# Формат возвращаемого сообщения:
{
  "status": "Success"/"Failure"/"Not supported",
  "message": "По какой причине был возвращен именно такой статус",
  // Определяет, использует ли драйвер методы attach/deatach
  "capabilities":{"attach": True/False}
}

使用方法 attach и detach 將定義 kubelet 將來呼叫驅動程式時將採取的場景。 還有一些特殊的方法 expandvolume и expandfs,它們負責動態調整磁碟區的大小。

作為該方法添加的更改的範例 expandvolume,並且能夠即時調整磁碟區大小,您可以熟悉 我們的拉取請求 在 Rook Ceph 操作員中。

以下是使用 NFS 的 Flexvolume 驅動程式的實作範例:

usage() {
    err "Invalid usage. Usage: "
    err "t$0 init"
    err "t$0 mount <mount dir> <json params>"
    err "t$0 unmount <mount dir>"
    exit 1
}

err() {
    echo -ne $* 1>&2
}

log() {
    echo -ne $* >&1
}

ismounted() {
    MOUNT=`findmnt -n ${MNTPATH} 2>/dev/null | cut -d' ' -f1`
    if [ "${MOUNT}" == "${MNTPATH}" ]; then
        echo "1"
    else
        echo "0"
    fi
}

domount() {
    MNTPATH=$1

    NFS_SERVER=$(echo $2 | jq -r '.server')
    SHARE=$(echo $2 | jq -r '.share')

    if [ $(ismounted) -eq 1 ] ; then
        log '{"status": "Success"}'
        exit 0
    fi

    mkdir -p ${MNTPATH} &> /dev/null

    mount -t nfs ${NFS_SERVER}:/${SHARE} ${MNTPATH} &> /dev/null
    if [ $? -ne 0 ]; then
        err "{ "status": "Failure", "message": "Failed to mount ${NFS_SERVER}:${SHARE} at ${MNTPATH}"}"
        exit 1
    fi
    log '{"status": "Success"}'
    exit 0
}

unmount() {
    MNTPATH=$1
    if [ $(ismounted) -eq 0 ] ; then
        log '{"status": "Success"}'
        exit 0
    fi

    umount ${MNTPATH} &> /dev/null
    if [ $? -ne 0 ]; then
        err "{ "status": "Failed", "message": "Failed to unmount volume at ${MNTPATH}"}"
        exit 1
    fi

    log '{"status": "Success"}'
    exit 0
}

op=$1

if [ "$op" = "init" ]; then
    log '{"status": "Success", "capabilities": {"attach": false}}'
    exit 0
fi

if [ $# -lt 2 ]; then
    usage
fi

shift

case "$op" in
    mount)
        domount $*
        ;;
    unmount)
        unmount $*
        ;;
    *)
        log '{"status": "Not supported"}'
        exit 0
esac

exit 1

因此,在準備好實際的可執行檔後,您需要 將驅動程式上傳到Kubernetes集群。 驅動程式必須按照預定的路徑位於每個叢集節點上。 預設已選擇:

/usr/libexec/kubernetes/kubelet-plugins/volume/exec/имя_поставщика_хранилища~имя_драйвера/

……但當使用不同的 Kubernetes 發行版(OpenShift、Rancher...)時,路徑可能會有所不同。

Flexvolume問題:如何正確拋竿?

事實證明,將 Flexvolume 驅動程式上傳到叢集節點並非易事。 手動完成一次操作後,很容易遇到叢集中出現新節點的情況:由於新增節點、自動水平擴展,或者更糟的是由於故障而更換節點。 在這種情況下,應該處理這些節點上的存儲 不可能,直到您仍然手動向其中新增 Flexvolume 驅動程式。

這個問題的解決方案是 Kubernetes 原語之一 - DaemonSet。 當叢集中出現新節點時,它會自動包含來自 DaemonSet 的 pod,本地磁碟區沿著尋找 Flexvolume 驅動程式的路徑附加到該 pod。 成功建立後,pod 會將驅動程式工作所需的檔案複製到磁碟。

以下是用於佈置 Flexvolume 插件的 DaemonSet 的範例:

apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  name: flex-set
spec:
  template:
    metadata:
      name: flex-deploy
      labels:
        app: flex-deploy
    spec:
      containers:
        - image: <deployment_image>
          name: flex-deploy
          securityContext:
              privileged: true
          volumeMounts:
            - mountPath: /flexmnt
              name: flexvolume-mount
      volumes:
        - name: flexvolume-mount
          hostPath:
            path: <host_driver_directory>

...以及用於佈置 Flexvolume 驅動程式的 Bash 腳本範例:

#!/bin/sh

set -o errexit
set -o pipefail

VENDOR=k8s.io
DRIVER=nfs

driver_dir=$VENDOR${VENDOR:+"~"}${DRIVER}
if [ ! -d "/flexmnt/$driver_dir" ]; then
  mkdir "/flexmnt/$driver_dir"
fi

cp "/$DRIVER" "/flexmnt/$driver_dir/.$DRIVER"
mv -f "/flexmnt/$driver_dir/.$DRIVER" "/flexmnt/$driver_dir/$DRIVER"

while : ; do
  sleep 3600
done

重要的是不要忘記複製操作 不是原子的。 kubelet 很有可能在其配置過程完成之前開始使用驅動程序,從而導致系統崩潰。 正確的方法是首先以不同的名稱複製驅動程式文件,然後使用原子重命名操作。

Kubernetes 儲存的磁碟區插件:從 Flexvolume 到 CSI
在 Rook Operator 中使用 Ceph 的示意圖:圖中的 Flexvolume 驅動程式位於 Rook 代理程式內部

使用 Flexvolume 驅動程式時的下一個問題是對於叢集節點上的大多數存儲 必須安裝必要的軟體 (例如,Ceph 的 ceph-common 包)。 最初,Flexvolume 插件並不是為了實現如此複雜的系統而設計的。

這個問題的原始解決方案可以在 Rook 操作符的 Flexvolume 驅動程式實作中看到:

驅動程式本身被設計為 RPC 客戶端。 用於通訊的IPC套接字與驅動程式本身位於同一目錄中。 我們記得,要複製驅動程式文件,最好使用 DaemonSet,它將目錄與驅動程式作為磁碟區連接起來。 複製必要的 rook 驅動程式檔案後,該 pod 不會消失,而是透過附加磁碟區作為成熟的 RPC 伺服器連接到 IPC 套接字。 ceph-common 軟體包已安裝在 pod 容器內。 IPC 套接字可確保 kubelet 將與位於相同節點上的 pod 進行準確通訊。 一切巧妙的事情都很簡單!...

再見,我們深情的...樹內插件!

Kubernetes 開發人員發現核心內用於儲存的插件數量為 XNUMX 個。 其中每一項的變更都會以某種方式貫穿整個 Kubernetes 發布週期。

事實證明,要使用新版本的儲存插件, 您需要更新整個集群。 除此之外,你可能會感到驚訝的是,新版本的Kubernetes 會突然與你正在使用的Linux 內核變得不相容......所以你擦乾眼淚,咬緊牙關,與你的管理層和使用者協調時間更新Linux核心和Kubernetes叢集。 提供服務可能會出現停機。

這種情況不只是滑稽,你不覺得嗎? 整個社區都清楚地意識到這種方法不起作用。 Kubernetes 開發人員故意宣布,核心將不再接受用於處理儲存的新插件。 此外,正如我們所知,在 Flexvolume 插件的實施過程中發現了一些缺陷...

Kubernetes 中最新加入的磁碟區插件 CSI 被要求一勞永逸地解決持久性資料儲存的問題。 它的 alpha 版本,更完整地稱為 Out-of-Tree CSI Volume Plugins,在發行版中宣布 庫伯內斯 1.9.

容器儲存接口,或CSI 3000旋轉桿!

首先,我想指出CSI不僅僅是一個卷插件,而是一個真正的 標準 建立用於資料倉儲的自訂元件。 Kubernetes 和 Mesos 等容器編排系統應該「學習」如何使用根據此標準實現的元件。 現在我已經學會 Kubernetes了。

Kubernetes 中的 CSI 插件的結構是怎麼樣的? CSI 插件與特殊驅動程式搭配使用(CSI 驅動程式)由第三方開發人員編寫。 Kubernetes 中的 CSI 驅動程式至少應包含兩個元件(pod):

  • 調節器 — 管理外部持久性儲存。 它被實作為 gRPC 伺服器,並使用原語 StatefulSet.
  • 節點 — 負責將持久性儲存安裝到叢集節點。 它也被實作為 gRPC 伺服器,但它使用原語 DaemonSet.

Kubernetes 儲存的磁碟區插件:從 Flexvolume 到 CSI
CSI 插件如何在 Kubernetes 中運作

您可以了解 CSI 工作的其他一些細節,例如,從文章“了解 C.S.I.其中的翻譯 我們一年前出版了。

這種實施方式的優點

  • 對於諸如為節點註冊驅動程式之類的基本操作,Kubernetes 開發人員實作了一組容器。 您不再需要像 Flexvolume 插件那樣自己產生帶有功能的 JSON 回應。
  • 我們現在將 Pod 上傳到集群,而不是將可執行檔「滑動」到節點上。 這是我們最初對 Kubernetes 的期望:所有程序都發生在使用 Kubernetes 原語部署的容器內。
  • 您不再需要開發 RPC 伺服器和 RPC 用戶端來實現複雜的驅動程式。 這個客戶端是由 Kubernetes 開發人員為我們實現的。
  • 透過 gRPC 協定傳遞參數比透過命令列參數傳遞參數更加方便、靈活且可靠。 要了解如何透過新增標準化 gRPC 方法來為 CSI 添加對磁碟區使用指標的支持,您可以閱讀: 我們的拉取請求 對於 vsphere-csi 驅動程式。
  • 通訊透過 IPC 套接字進行,以免混淆 kubelet 是否將請求傳送到正確的 pod。

這份清單讓你想起什麼了嗎? CSI的優點是 解決同樣的問題,開發 Flexvolume 插件時沒有考慮到這一點。

發現

CSI 作為實現與資料倉儲互動的自訂插件的標準受到了社群的熱烈歡迎。 此外,由於其優點和多功能性,甚至為 Ceph 或 AWS EBS 等儲存系統創建了 CSI 驅動程序,在 Kubernetes 的第一個版本中添加了用於使用這些系統的插件。

2019年初,樹內插件 已被宣布過時。 我們計劃繼續支援 Flexvolume 插件,但不會為其開發新功能。

我們自己已經擁有使用 ceph-csi、vsphere-csi 的經驗,並準備將其添加到此列表中! 到目前為止,CSI 正在出色地處理分配給它的任務,但我們將拭目以待。

不要忘記,一切新事物都是對舊事物的良好反思!

聚苯乙烯

另請閱讀我們的博客:

來源: www.habr.com

添加評論