iSCSIを封じ込めるための道のり

iSCSIは、iSCSIイニシエータ(クライアント)がネットワークを介してiSCSIターゲット(ストレージサーバ)と通信する、ブロックレベルのストレージアクセスの一般的なプロトコルです。 iSCSI ターゲットは、1 つ以上の LUN の形式でイニシエータにストレージを提供します。

iSCSIを活用して、コンテナ化されたワークロードに永続ストレージを提供できます。 Kubernetes では、iSCSI イニシエーターの操作は、ワーカー ノードで直接実行されるプロセスによって管理されます。 ただし、このようなイニシエーター操作をコンテナー内から管理することが不可欠になる状況もあります。 コンテナー オーケストレーターのコンテナーとしてストレージ プラグインを開発し、コンテナー内で kubelet を実行することは、一般的なユース ケースです。 たとえば、現在、Docker Kubernetes Service (DKS) は kubelet をコンテナーとして実行し、Linux ワークロード用のツリー内 (Kubernetes に付属) iSCSI プラグインのサポートを提供しています。

ただし、iSCSIコンポーネントはコンテナを念頭に置いて設計されていないため、コンテナ内からiSCSIを管理するのは困難です。 このブログでは、LinuxでiSCSIをコンテナ化できるようにするために検討されたさまざまなオプションを共有しています。

iSCSI コンポーネントの概要

iSCSI サポートを提供するために、Kubernetes は標準の Linux iSCSI 実装である open-iscsi に依存しています。 オープン iSCSI パッケージは、クラスター ノードにインストールされることが想定されています。open-iscsi パッケージは以下を提供します。

  • iscsiadm – iSCSI管理ツール
  • iscsid – iSCSI デーモンプロセス

データパスを実装するiSCSIカーネルモジュールは、ホストカーネルの一部としてロードおよび管理されます。

Kubernetes は iscsiadm を使用してノード上で iSCSI コマンドを実行します。 たとえば、kubeletは、 iscsiadm コマンドを実行して、ノードへの永続ボリュームのアタッチとデタッチ、およびポッドへの永続ボリュームのマウントとマウント解除を実行します。 ツリー内プラグインとは別に、iSCSIは CSI (コンテナストレージインターフェイス)プラグインでもサポートされています。
iSCSIADM は、iSCSI および iSCSI カーネルモジュールと連携して動作します。 iscsiadm と iscsid は Unix ドメインソケットを介して通信します。iSCSI は ネットリンク ソケットを介してカーネルモジュールと通信します。 カーネルのnetlink制御コードは ネットワーク名前空間に対応していない ことに注意してください(1)

ブログ iSCSI コンポーネント 1

コンテナの場合

iscsiadm バイナリの呼び出しが、ホスト プロセスからではなくコンテナーから行われる場合があります。このブログの残りの部分では、このようなコンテナーを "iscsiadm コンテナー" と呼びます。 コンテナからiSCSIを管理する一般的な使用例は次のとおりです。

    • コンテナ化されたクベレット:

Kubelet はコンテナーとして実行されます。 通常、kubeletはホストプロセスとして実行されます。 ただし、Kubernetesコンポーネントをコンテナ化すると、バイナリ配布が容易になり、予測可能なセットアップが統一されるようになりました。 また、開発/テスト環境でも非常に貴重であることが証明されています。 このような場合、kubelet は他の Kubernetes コンポーネントと共にコンテナで実行されます。

    • コンテナ化されたCSIプラグイン:

通常、CSIボリュームプラグインには、コントローラプラグインとノードプラグインの2つのコンポーネントがあります。 このようなプラグインは、Kubernetes デプロイ (コントローラー プラグイン) とデーモンセット (ノード プラグイン) としてデプロイするのが一般的です。 したがって、iSCSIをサポートするCSIプラグインは、 iscsiadm コマンドを発行できるコンテナとして配布する必要があります。 iscsiadm は CSI ノードプラグインによって呼び出されることに注意してください。

さまざまなディストリビューションでのオープンiSCSI

最近のほとんどのLinuxディストリビューションは、オープンiSCSIプロジェクトを使用して iSCSI パッケージをビルドします。 ディストリビューションが異なれば、使用するオープン iscsi のバージョンも異なります。 open-iscsi の一部のバージョンには、追加のライブラリ依存関係があります。私たちの実験は以下を明らかにしました:

  • オープンiSCSIバージョン2.0.874 インターネットストレージネームサービス(iSNS)の実装である新しいライブラリ libisns0への依存関係を導入しました。 たとえば、このバージョンの オープンiscsi はUbuntu18.04で使用されます。
  • オープンiSCSIバージョン2.0.876 新しいライブラリである libopeniscsiusr、 iSCSI ユーザーレベルライブラリへの依存関係が導入されました。 たとえば、このバージョンの オープンiSCSI はSLES 15の一部として出荷されます。

これらの依存関係は、コンテナーがライブラリにもアクセスできる必要があることを意味します。

パッケージ化とランタイムの選択

iSCSI コンポーネントをパッケージ化して実行するには、いくつかのオプションがあります。 iscsiadmコンテナの異なる基本イメージを持つ一連のLinuxディストリビューションで実験を実行しました。 次の3つのオプションで調査結果の概要を説明しました。

オプション 1:

オープン iSCSI パッケージを iscsiadm コンテナにインストールします。コンテナーを実行します。

  • カーネルモジュールをロードするSYS_MODULE機能を備えています(dockerは–cap-add SYS_MODULEを実行します)。
  • ホストネットワーク名前空間内。 上記(1)により、iscsidを実行しているコンテナは、ホストネットワーク名前空間にアクセスできる必要があります

コンテナーで iscsidiscsiadm を呼び出します。

短所:

  • ホスト ネットワーク名前空間でコンテナーを実行すると、ホストからの iscsid がコンテナーからの iscsid に干渉し、その逆も同様であるため、実行できる iscsid インスタンスは 1 つだけになります。 そのため、ホストが iscsid を実行しないようにし、さらにホストから iSCSI パッケージを削除するように注意する必要があります。 一部のLinuxディストリビューションでは、iscsidが有効になっていて、デフォルトで実行されています(例: Ubuntu 16.04 Amazon Machine Image (AMI))。 このような場合、netlink ソケット通信をブロックし、コンテナから iscsid の別のインスタンスが起動するのを防ぎます。 また、systemdベースのディストリビューションでは、ホストでのsystemdソケットのアクティブ化により、サービスが実行されていない場合でもソケットがビジー状態になります。 そのため、iSCSIホストパッケージ全体をホストから削除する必要があります。 (例えば、 'yum remove iscsi-initiator-tools' または 'apt-get remove open-iscsi')。
    • カーネルモジュールのロードは、 kmod (insmod /modprobe は kmod へのシンボリックリンクです) バイナリを使用して行われます。 iscsiadm コンテナイメージとホストの kmod バージョンは異なる場合があります。たとえば、RHEL 7.5 ホストと ubuntu 18.04 iscsiadm コンテナー イメージでは、kmod のバージョンはそれぞれ 20 と 24 です。 その結果、コンテナから iscsi_tcp モジュールをmodprobingすると、kmodの潜在的な後方互換性の問題が原因でexecフォーマットエラーが発生します。

ブログモッドプローブ


したがって、カーネルモジュールはホストから管理する必要があり、コントロールプレーンコンポーネント(iscsiadmおよびiscsid)はコンテナによって管理する必要があります。 これはすっきりとしたデザインではありません。
  • 別の目的(kubelet、CSIノードプラグインバイナリなど)を目的としたコンテナの一部として iscsid などのシステムデーモンを実行すると、コンテナごとに1つのアプリケーションに関するゴールデンコンテナ化ルールが破られます。

オプション 2: 
ホストにオープンiSCSIをインストールし、ホスト上でiSCSIDを実行します。コンテナーに open-iscsi をインストールし、コンテナーから iscsiadm を呼び出します。 ホスト ネットワーク名前空間でコンテナーを実行します。 ここで、 iscsiadmコンテナはホストのiscsid にアクセスしますが、これは両方のプロセスが同じネットワーク名前空間で実行されているために可能です。

短所:

  • 任意のバージョンの iscsiadmiscsid 間の通信を制御する標準プロトコルはありません。一般的なディストリビューション全体のテストでは、 iscsiadm バイナリは同じバージョンのパッケージの iscsid バイナリでのみ機能するように見えました。 このバイナリ互換性は、異なるLinuxホストディストリビューション間での作業中には保証されません。

オプション 3: 

ホストにオープンiSCSIをインストールし、ホスト上でiSCSIDを実行します。 ホストルートファイルシステムでマウントされたコンテナバインドを実行します (docker run -v /:/host <container> <entrypoint>))。 次に、次のいずれかのソリューションを使用します。

        • コンテナのエントリポイントスクリプトの一部として、ホストからコンテナファイルシステムにiscsiadmとiscsiデータベースをシンボリックリンクします。 ホストライブラリパスをコンテナのライブラリパス設定に追加して、ホストライブラリが検索パスに含まれるようにします。

      ブログのホストリンク

      • ルートをホストルートファイルシステムに設定し、PATH を適切なホストビンディレクトリに設定して、iscsiadm の chroot 環境を作成します。 これを "iscsiadm" という名前のスクリプトに追加します。

ブログネットアップのchroot


このファイルをコンテナー イメージに追加し、適切なアクセス許可を付与します。
ブログネットアップ追加
これにより、コンテナによる iscsiadm の呼び出しごとに、上記の chroot スクリプトが呼び出されるようになります。 ネットアップ Trident はこのソリューションを使用して、Docker ボリューム プラグインをコンテナー化します。

短所:

      • コンテナをバインドマウントするには、ホスト rootfs (または /sbin、/usr/sbin、/etc、/lib64、/usr/lib64 などの特定のホストシステムディレクトリ) が必要です。

長所:

      • これはクリーンで邪魔にならないオプションです。

 

オプション 1 と 2 は、ソリューションで複数の Linux ホスト配布をサポートする必要がある場合は機能しません。 オプション 3 は、異種 Linux ディストリビューションのセット全体でコンテナー化された iSCSI 環境をサポートするためのクリーンな方法です。 上記のオプション 3 を選択すると、異なる Linux ホスト ディストリビューションの依存関係が正しく処理されます。

iSCSI環境のコンテナ化中に障害が発生することが予想されます。 Docker Enterprise 3.0のiSCSIサポートを構築しているときにいくつかに遭遇し、ここで調査とベストプラクティスを文書化しました。 これがストレージプラグインの作成者とアップストリームのkubernetes開発者にとって有用なガイドになることを願っています。