1. はじめに
本記事は、Kubernetes 上で利用可能な NFS 系ストレージの方式を整理し、それぞれのアーキテクチャ、可用性、I/O 特性、そして KubeVirt / SUSE Harvester での仮想マシン(VM)ブートとの関係を明らかにすることを目的とした机上調査です。
一部、筆者の検証環境での実機確認結果を含みますが、未検証の推測も含まれます。推測箇所にはその旨を明記しています。
シリーズ記事
| 回 | タイトル | URL |
|---|---|---|
| 第1回 | Proxmox VE で SUSE Harvester を試す | https://qiita.com/flathill/items/10145b46dc71fdedb60f |
| 第2回 | SUSE Harvester に TrueNAS iSCSI ストレージを追加する | https://qiita.com/flathill/items/aaca2f47acec54357e77 |
| 第3回 | SUSE Harvester に NFS CSI ドライバを導入して共有ストレージを構成する | https://qiita.com/flathill/items/b94d008b65b2c074b83c |
| 第4回 | SUSE Harvester で 3 種類のデータストアから仮想マシンを起動する | https://qiita.com/flathill/items/d33b149386b06da8fb58 |
| 第5回 | SUSE Harvester ストレージベンチマーク — Longhorn / iSCSI / NFS 3方式比較 | https://qiita.com/flathill/items/a177caec47a0eaf7d28f |
2. NFS 系ストレージの3つのアーキテクチャ
Kubernetes で NFS を利用するアプローチは大きく3つに分類できます。
2.1 方式A: 外部 NFS サーバ直接接続型(csi-driver-nfs)
クラスタ外部に存在する既存の NFS サーバに対して、CSI ドライバがサブディレクトリを動的に作成・削除する方式です。NFS サーバ自体の構築・管理は Kubernetes の管理外であり、TrueNAS や NetApp などのストレージアプライアンスを利用するケースが典型的です。
代表的な実装は Kubernetes SIG が管理する csi-driver-nfs(provisioner 名: nfs.csi.k8s.io)です。
この方式の特徴は、NFS サーバ Pod をクラスタ内にデプロイしないことです。I/O パスは「VM → NFS カーネルクライアント → ネットワーク → 外部 NFS サーバ」と短く、NFS サーバの可用性・性能はアプライアンス側に依存します。本シリーズの第3回〜第5回で TrueNAS Scale + Harvester 環境に導入・検証を行いました。
2.2 方式B: PVC ごとに NFS サーバ Pod を自動生成する型
PVC が作成されるたびに、クラスタ内に NFS サーバ Pod を自動デプロイし、その Pod がバックエンドのブロックストレージ(iSCSI、FC、ローカルディスク等)を NFS で公開する方式です。
代表的な実装として HPE CSI Driver NFS Server Provisioner と OpenEBS Dynamic NFS Provisioner があります。
この方式では、PVC ごとに独立した NFS サーバ Pod + バックエンド PVC + Service が自動生成されます。アプリケーションから見ると通常の NFS マウントですが、裏側ではブロックストレージを NFS に変換する Pod が仲介しています。
HPE と OpenEBS の主な差異は以下の通りです。
| 項目 | HPE CSI NFS Server Provisioner | OpenEBS Dynamic NFS Provisioner |
|---|---|---|
| バックエンド | HPE ストレージ(Alletra 等)またはForeign StorageClass | 任意の StorageClass |
| provisioner 名 | csi.hpe.com |
openebs.io/nfsrwx |
| Pod Monitor(自動復旧) | あり(30秒間隔) | なし(Deployment の再スケジュールに依存) |
| ベンダー依存 | HPE ストレージが必要(Foreign SC利用時を除く) | なし(オープンソース) |
参考: HPE 公式ブログ — Introducing an NFS Server Provisioner、OpenEBS Dynamic NFS Provisioner ドキュメント
2.3 方式C: 共有 NFS サーバ Pod 型(nfs-ganesha-server-and-external-provisioner)
クラスタ内に NFS Ganesha サーバ Pod を1つデプロイし、その配下にサブディレクトリを動的プロビジョニングする方式です。方式A の「外部 NFS サーバ」をクラスタ内の Pod として実現したものと考えることができます。
代表的な実装は Kubernetes SIG が管理する nfs-ganesha-server-and-external-provisioner です。
方式B との違いは、NFS サーバ Pod がクラスタ全体で1つであり、PVC ごとにサブディレクトリで分離する点です。Pod 数が少なくリソース効率は良いですが、この1つの Pod が全 PVC のシングルポイントになります。
参考: nfs-ganesha-server-and-external-provisioner — GitHub
2.4 3方式の比較表
| 項目 | 方式A: 外部 NFS 直接接続 | 方式B: PVC ごと NFS Pod | 方式C: 共有 NFS Pod |
|---|---|---|---|
| 代表実装 | csi-driver-nfs | HPE CSI / OpenEBS | nfs-ganesha-server |
| NFS サーバの場所 | クラスタ外部 | クラスタ内(PVC ごとに1つ) | クラスタ内(全体で1つ) |
| NFS サーバ Pod | なし | PVC 数と同数 | 1つ |
| バックエンド | 外部 NFS 共有 | 任意のブロック StorageClass | 任意のボリューム |
| I/O パスの長さ | 短い | 長い(Pod を経由) | 長い(Pod を経由) |
| ベンダー依存 | NFS サーバの準備が必要 | HPE 版は HPE ストレージ必要 | なし |
| 外部 NFS サーバの要否 | 必要 | 不要 | 不要 |
3. 可用性とシングルポイント障害
3つの方式はそれぞれシングルポイント障害の所在と影響範囲が異なります。
方式A(外部 NFS サーバ直接接続) では、外部 NFS サーバ自体がシングルポイントです。NFS サーバが停止すると全ノードから全 PVC にアクセスできなくなります。ただし、TrueNAS の HA 構成や NetApp の冗長化など、アプライアンス側での対策が可能です。クラスタ内の csi-nfs-controller Pod が停止しても、既存のマウントには影響しません(新規 PVC の作成・削除のみ不可)。この動作は第3回の記事で確認しています。
方式B(PVC ごとに NFS サーバ Pod を生成) では、各 NFS サーバ Pod がそれぞれの PVC に対するシングルポイントです。ある NFS サーバ Pod が停止すると、その PVC を使うワークロードのみ影響を受け、他の PVC は正常に動作し続けます。Pod は Deployment で管理されるため Kubernetes が自動的に再スケジュールしますが、再起動中はダウンタイムが発生します。HPE の実装では Pod Monitor(30秒間隔)による検知・復旧機構が提供されています(参考: HPE SCOD — Pod Monitor)。なお、GitHub Issue #450 では、NFS サーバ Pod が別ノードに移動した際に「Stale file handle」が発生するケースが報告されています。
方式C(共有 NFS サーバ Pod) では、クラスタに1つだけ存在する NFS サーバ Pod がシングルポイントです。この Pod が停止すると、全ての NFS PVC にアクセスできなくなります。影響範囲が最も広い方式です。
| 方式 | シングルポイント | 障害影響範囲 | 自動復旧 |
|---|---|---|---|
| A: 外部 NFS 直接接続 | 外部 NFS サーバ | 全 PVC | アプライアンス側 HA |
| B: PVC ごと NFS Pod | 各 NFS サーバ Pod | 該当 PVC のみ | Deployment 再スケジュール(+ HPE は Pod Monitor) |
| C: 共有 NFS Pod | 共有 NFS サーバ Pod | 全 PVC | Deployment 再スケジュール |
4. I/O パフォーマンス特性
NFS 系ストレージの I/O パフォーマンスは、I/O パスの長さとボトルネックの所在によって大きく異なります。
方式A の I/O パスは「VM → ノードの NFS カーネルクライアント → ネットワーク → 外部 NFS サーバ」です。Pod を介さないため、NFS サーバのディスク性能、CPU、メモリ(キャッシュ)、ネットワーク帯域がそのまま I/O パフォーマンスに反映されます。第5回のベンチマークでは、TrueNAS の ZFS ARC キャッシュが効いたこともあり、NFS が Longhorn(ローカルディスク3レプリカ)を上回る結果となりました。
方式B・C の I/O パスは「VM → NFS カーネルクライアント → ネットワーク → NFS サーバ Pod → Pod 内ファイルシステム → バックエンド PVC(iSCSI 等) → ストレージ」と長くなります。NFS サーバ Pod が仲介するため、以下のボトルネックが追加されます。
- Pod の CPU/メモリ制限: HPE の場合、デフォルトで CPU 1000m、メモリ 2048Mi に制限されています(参考: HPE SCOD — StorageClass Parameters)。NFS サーバはキャッシュに多くのメモリを使うため、この制限が I/O スループットの上限に直結します。
- ユーザスペース処理: NFS Ganesha(方式B・C で利用)はユーザスペースで動作するため、カーネル NFS サーバ(方式A の TrueNAS 等が使用)と比較してコンテキストスイッチのオーバーヘッドが発生します。
- 二重のネットワーク経路: クライアント → NFS サーバ Pod が NFS プロトコル、NFS サーバ Pod → バックエンドストレージが iSCSI/FC プロトコルと、2段のネットワーク通信が発生し、レイテンシが加算されます。
実効パフォーマンスは「NFS サーバ Pod のリソース制限」と「バックエンドストレージの性能」の低い方で律速されます。Pod ベースの NFS サーバを選択する動機は性能ではなく、「外部 NFS サーバを用意できない環境で、ブロックストレージから RWX を実現する」というアーキテクチャ上の制約解消です。
5. KubeVirt / Harvester での VM ブートの仕組み
5.1 KubeVirt の2つの volumeMode
KubeVirt は PVC を VM のディスクとして利用する際、2つの volumeMode をサポートしています。
-
volumeMode: Block— PVC を Raw ブロックデバイスとして VM に直接提供します。Longhorn や iSCSI など、ブロックストレージで一般的な方式です。 -
volumeMode: Filesystem— PVC 上のファイルシステムにdisk.imgというファイルを配置し、それを VM のディスクとして利用します。
KubeVirt の公式ドキュメントには以下の記載があります。
A PersistentVolume can be in "filesystem" or "block" mode:
- Filesystem: For KubeVirt to be able to consume the disk present on a PersistentVolume's filesystem, the disk must be named
disk.imgand be placed in the root path of the filesystem.
参考: KubeVirt User Guide — Filesystems, Disks and Volumes
つまり、volumeMode: Filesystem での VM ブートは KubeVirt の正式な機能であり、フォールバックやワークアラウンドではありません。
5.2 CDI の StorageProfile による volumeMode の自動決定
Harvester が内部で利用する CDI(Containerized Data Importer)は、StorageClass ごとに StorageProfile というリソースを自動生成します。StorageProfile には、その StorageClass で PVC を作成する際に使用する volumeMode と accessModes が定義されています。
CDI は provisioner 名に基づいて StorageProfile を自動設定します。CDI のソースコードには、既知の provisioner に対するデフォルトの volumeMode / accessModes のマッピングが定義されています(参考: CDI storagecapabilities.go)。
CDI が認識しない provisioner の場合は、StorageClass にアノテーション cdi.harvesterhci.io/storageProfileVolumeModeAccessModes を手動で付与することで StorageProfile を設定できます。
Harvester v1.6 の Third-Party Storage Support ドキュメントにも以下の注記があります。
If the StorageClass provisioner is not in the CDI's list of provisioners with default access and volume modes, you must annotate the StorageClass with
cdi.harvesterhci.io/storageProfileVolumeModeAccessModes.
参考: Harvester v1.6 — Third-Party Storage Support
5.3 今回の検証での実機確認結果
筆者の Harvester v1.7.1 検証環境で、VM ディスク用 PVC の volumeMode を確認した結果は以下の通りです。
kubectl get pvc -n default -o custom-columns=NAME:.metadata.name,VOLUMEMODE:.spec.volumeMode,STORAGECLASS:.spec.storageClassName
| PVC | volumeMode | StorageClass |
|---|---|---|
| test-longhorn-vm-disk-0-... | Block | longhorn-image-hjpz6 |
| test-iscsi-vm-disk-0-... | Block | longhorn-image-dsnm9 |
| test-nfs-vm-disk-0-... | Filesystem | nfs-csi |
Longhorn 系の VM ディスクは volumeMode: Block で作成され、NFS CSI の VM ディスクは volumeMode: Filesystem で作成されています。Harvester / CDI が StorageClass の能力に応じて volumeMode を自動的に切り替えていることが実機で確認できた事実です。
6. 各方式で VM ブートは可能か
6.1 方式A: csi-driver-nfs — Harvester 公式サポート(検証済み)
Harvester v1.5 以降、nfs.csi.k8s.io は検証済み CSI ドライバとして公式ドキュメントに記載されており、VM Root Disk を含む全機能が ✔ となっています。
| 機能 | NFS(nfs.csi.k8s.io) |
|---|---|
| VM Image | ✔ |
| VM Root Disk | ✔ |
| VM Data Disk | ✔ |
| VM Live Migration | ✔ |
参考: Harvester v1.6 — Third-Party Storage Support
本シリーズの第4回で、実際に nfs-csi StorageClass で VM を作成し、正常に起動することを確認しています。
6.2 方式B: HPE CSI NFS Server Provisioner — 技術的には可能と推測(未検証)
HPE の公式ドキュメント(SCOD)の Red Hat OpenShift ページには以下の記載があります。
Do not attempt to boot or image OpenShift Virtualization virtual machines
参考: HPE SCOD — Red Hat OpenShift
ただし、この制約は OpenShift Virtualization に対するものです。 同じ SCOD の SUSE Virtualization(Harvester)ページでは、HPE CSI Driver で VM のブートが可能であることが記載されています(Harvester 1.5.0 以降)。
Booting VMs from a HPE CSI Driver backed volume requires Harvester 1.5.0 or newer.
参考: HPE SCOD — SUSE Virtualization
ここでの「HPE CSI Driver backed volume」はブロックストレージ(iSCSI/FC)を指していますが、前述の通り、Harvester の CDI は StorageProfile に基づいて volumeMode を決定します。HPE CSI NFS Server Provisioner が提供する NFS ボリュームに対して StorageProfile を volumeMode: Filesystem に設定すれば、CDI が disk.img 方式で VM ディスクを作成し、VM ブートが可能になると推測されます。
推測: HPE CSI NFS Server Provisioner + Harvester での VM ブートは技術的な仕組みとして矛盾はありませんが、筆者の環境には HPE ストレージがないため未検証です。
6.3 方式B: OpenEBS Dynamic NFS Provisioner — 技術的には可能と推測(次回検証予定)
OpenEBS Dynamic NFS Provisioner はベンダー非依存であり、バックエンドに harvester-longhorn などの既存 StorageClass を指定できます。アプリケーションから見れば NFS マウントされたファイルシステムであり、disk.img を配置できる点は csi-driver-nfs と同じです。
StorageProfile を正しく設定すれば、Harvester 上で VM ブートが可能と推測されます。次回の記事で実機検証を行う予定です。
推測: OpenEBS Dynamic NFS Provisioner + Harvester での VM ブートは未検証です。次回記事で検証予定。
6.4 方式C: nfs-ganesha-server — 技術的には可能と推測(次々回検証予定)
nfs-ganesha-server-and-external-provisioner も、最終的にアプリケーションから見れば NFS マウントされたファイルシステムです。StorageProfile が正しく設定されれば、CDI が volumeMode: Filesystem で PVC を作成し、VM ブートが可能と推測されます。
推測: nfs-ganesha-server + Harvester での VM ブートは未検証です。次々回記事で検証予定。
6.5 VM ブート可否のまとめ
| 方式 | 実装 | VM ブート | 根拠 |
|---|---|---|---|
| A | csi-driver-nfs | ✔ 検証済み | Harvester 公式サポート + 筆者の実機検証 |
| B | HPE CSI NFS Server Provisioner | 推測: 可能 | KubeVirt の Filesystem モード + CDI StorageProfile の仕組みから |
| B | OpenEBS Dynamic NFS Provisioner | 推測: 可能(次回検証) | 同上 |
| C | nfs-ganesha-server | 推測: 可能(次々回検証) | 同上 |
いずれの方式も、VM ブートが可能となる条件は共通しています。
- CDI の StorageProfile で
volumeMode: Filesystemが設定されていること - CDI が認識しない provisioner の場合は、アノテーション
cdi.harvesterhci.io/storageProfileVolumeModeAccessModesを手動で付与すること - NFS 共有のパーミッション設定で、KubeVirt の QEMU UID/GID がファイルに書き込めること
7. まとめと次回予告
本記事では、Kubernetes の NFS 系ストレージを3つのアーキテクチャに分類し、可用性、I/O 特性、VM ブートとの関係を整理しました。
NFS 系ストレージの選定指針
- 性能重視・外部 NFS サーバを用意できる場合 → 方式A(csi-driver-nfs)が最適です。Pod を介さないため I/O パスが短く、NFS サーバ側のキャッシュやディスク性能を直接活用できます。
- 外部 NFS サーバを用意できないが RWX が必要な場合 → 方式B(OpenEBS / HPE)が候補です。ブロックストレージしかない環境でも RWX を実現できますが、NFS サーバ Pod のリソース制限がボトルネックになる点と、Pod がシングルポイントになる点を考慮する必要があります。
- シンプルな構成でクラスタ内 NFS を実現したい場合 → 方式C(nfs-ganesha-server)が候補ですが、1つの Pod が全 PVC のシングルポイントになるため、障害影響範囲が最も広くなります。
次回予告
- 次回: OpenEBS Dynamic NFS Provisioner を Harvester 環境にデプロイし、VM ブートが可能かを実機検証します。
- 次々回: nfs-ganesha-server-and-external-provisioner の実機検証を行います。