Kubernetes ストレージのボリューム プラグイン: Flexvolume から CSI まで

Kubernetes ストレージのボリューム プラグイン: Flexvolume から CSI まで

Kubernetes がまだ v1.0.0 だった頃、ボリューム プラグインがありました。 これらは、システムを Kubernetes に接続して永続的な (永続的な) コンテナー データを保存するために必要でした。 その数は少なく、最初のプロバイダーには GCE PD、Ceph、AWS EBS などのストレージ プロバイダーがありました。

プラグインは Kubernetes とともに配信されたため、インツリーという名前が付けられました。 しかし、多くの人にとって、そのようなプラグインの既存のセットでは不十分であることが判明しました。 職人たちはパッチを使用して簡単なプラグインを 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 プリミティブの XNUMX つでした。 DaemonSet。 新しいノードがクラスターに表示されると、そのノードには DaemonSet のポッドが自動的に含まれます。このポッドには、Flexvolume ドライバーを見つけるためのパスに沿ってローカル ボリュームが接続されます。 作成が成功すると、ポッドはドライバーが動作するために必要なファイルをディスクにコピーします。

以下は、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 オペレーターでの Ceph の操作の図: 図の Flexvolume ドライバーは Rook エージェント内にあります

Flexvolume ドライバーを使用する場合の次の問題は、クラスター ノード上のほとんどのストレージで問題が発生することです。 これに必要なソフトウェアをインストールする必要があります (たとえば、Ceph の ceph-common パッケージ)。 当初、Flexvolume プラグインは、このような複雑なシステムを実装するように設計されていませんでした。

この問題に対する独自の解決策は、Rook オペレーターの Flexvolume ドライバー実装に見ることができます。

ドライバー自体は RPC クライアントとして設計されています。 通信用の IPC ソケットは、ドライバー自体と同じディレクトリにあります。 ドライバー ファイルをコピーするには、ディレクトリとドライバーをボリュームとして接続する DaemonSet を使用するとよいことを覚えています。 必要な Rook ドライバー ファイルをコピーした後、このポッドは停止せず、接続されたボリュームを介して本格的な RPC サーバーとして IPC ソケットに接続します。 ceph-common パッケージはポッド コンテナ内にすでにインストールされています。 IPC ソケットにより、kubelet が同じノード上にあるポッドと正確に通信できるようになります。 独創的なものはすべてシンプルです!

さようなら、私たちの愛情深い... ツリー内プラグイン!

Kubernetes 開発者は、コア内のストレージ用のプラグインの数が XNUMX であることを発見しました。 そして、それぞれの変更は、何らかの形で、Kubernetes リリース サイクル全体を通じて行われます。

新しいバージョンのストレージ プラグインを使用するには、 クラスター全体を更新する必要がある。 これに加えて、Kubernetes の新しいバージョンが、使用している Linux カーネルと突然互換性がなくなることに驚くかもしれません... そこで、あなたは涙をぬぐい、歯を食いしばりながら、管理者やユーザーと時間を調整して、 Linux カーネルと Kubernetes クラスターを更新します。 サービスの提供中にダウンタイムが発生する可能性があります。

この状況は滑稽以上のものだと思いませんか? このアプローチが機能していないことがコミュニティ全体に明らかになりました。 Kubernetes 開発者は、意図的な決定により、ストレージを操作するための新しいプラグインがカーネルに受け入れられなくなることを発表しました。 さらに、すでにご存知のとおり、Flexvolume プラグインの実装には多くの欠点が判明しました。

Kubernetes のボリューム用に最新に追加されたプラグインである CSI は、永続的なデータ ストレージの問題を完全に解決するために必要とされました。 そのアルファ版は、より完全には Out-of-Tree CSI Volume Plugins と呼ばれ、リリースで発表されました。 Kubernetes 1.9.

コンテナ ストレージ インターフェイス、または CSI 3000 スピニング ロッド!

まず最初に、CSI は単なるボリュームプラグインではなく、本物のボリュームプラグインであることに注意してください。 стандарт データ ウェアハウスを操作するためのカスタム コンポーネントの作成について。 Kubernetes や Mesos などのコンテナ オーケストレーション システムは、この標準に従って実装されたコンポーネントの操作方法を「学習」することになっていました。 そして今、私はすでに Kubernetes を学びました。

Kubernetes の CSI プラグインの構造は何ですか? CSI プラグインは特別なドライバー (CSIドライバー)サードパーティの開発者によって書かれています。 Kubernetes の CSI ドライバーは、少なくとも XNUMX つのコンポーネント (ポッド) で構成されている必要があります。

  • コントローラー — 外部永続ストレージを管理します。 gRPC サーバーとして実装され、プリミティブが使用されます。 StatefulSet.
  • Node — 永続ストレージをクラスター ノードにマウントする役割を果たします。 gRPC サーバーとしても実装されていますが、プリミティブを使用します。 DaemonSet.

Kubernetes ストレージのボリューム プラグイン: Flexvolume から CSI まで
Kubernetes での CSI プラグインの仕組み

CSI の活動のその他の詳細については、たとえば記事「C.S.I. を理解する" どれの翻訳 私たちはXNUMX年前に出版しました。

このような実装の利点

  • ノードのドライバーの登録などの基本的なことのために、Kubernetes 開発者は一連のコンテナーを実装しました。 Flexvolume プラグインの場合のように、機能を備えた JSON 応答を自分で生成する必要はなくなりました。
  • 実行可能ファイルをノードに「スリップ」する代わりに、ポッドをクラスターにアップロードするようになりました。 これが私たちが最初に Kubernetes に期待していることです。すべてのプロセスは、Kubernetes プリミティブを使用してデプロイされたコンテナー内で発生します。
  • 複雑なドライバーを実装するために RPC サーバーと RPC クライアントを開発する必要はなくなりました。 クライアントは Kubernetes 開発者によって実装されました。
  • gRPC プロトコル経由で引数を渡す方が、コマンド ライン引数経由で渡すよりもはるかに便利で、柔軟性があり、信頼性が高くなります。 標準化された gRPC メソッドを追加してボリューム使用量メトリクスのサポートを CSI に追加する方法を理解するには、以下を参照してください。 私たちのプルリクエスト vsphere-csi ドライバー用。
  • kubelet が正しいポッドにリクエストを送信したかどうかを混乱しないように、通信は IPC ソケット経由で行われます。

このリストを見て何か思い出したことはありますか? CSIの利点は次のとおりです。 それらと同じ問題を解決する、Flexvolume プラグインの開発時には考慮されませんでした。

所見

データ ウェアハウスと対話するためのカスタム プラグインを実装するための標準としての CSI は、コミュニティから非常に温かく受け入れられました。 さらに、CSI ドライバーはその利点と汎用性により、Ceph や AWS EBS などのストレージ システム用にも作成されており、これらと連携するためのプラグインは Kubernetes の最初のバージョンで追加されました。

2019 年の初めに、ツリー内プラグイン 時代遅れと宣言されました。 Flexvolume プラグインは引き続きサポートする予定ですが、新しい機能は開発しません。

私たち自身もすでに ceph-csi、vsphere-csi の使用経験があり、このリストに追加する準備ができています。 これまでのところ、CSI は割り当てられたタスクに順調に対処していますが、様子見となります。

新しいものはすべて古いものを再考したものであることを忘れないでください。

PS

私たちのブログもお読みください:

出所: habr.com

コメントを追加します