はじめに
本記事は、自宅ラボで SUSE Harvester(HCI)を構築・拡張するシリーズの第3回です。
| 回 | 内容 | 記事リンク |
|---|---|---|
| 第1回 | Proxmox VE 上に Harvester v1.7.1 の3ノードクラスタを構築 | Proxmox VE で SUSE Harvester を試す |
| 第2回 | TrueNAS Scale の iSCSI LUN を Longhorn ストレージとして追加 | SUSE Harvester に TrueNAS iSCSI ストレージを追加する |
| 第3回 | NFS CSI ドライバを導入し共有ストレージを構成(本記事) | — |
第2回では TrueNAS Scale の iSCSI LUN を Longhorn のディスクとして登録し、StorageClass longhorn-iscsi を作成しました。今回は同じ TrueNAS Scale の NFS 共有を Kubernetes の CSI ドライバ経由で利用できるようにし、Pod 間で共有可能なストレージ(ReadWriteMany)を構成します。
iSCSI(Longhorn)と NFS CSI の違い
第2回で導入した iSCSI ストレージは Longhorn が管理するブロックストレージであり、ディスクを各ノードに登録してレプリカを分散配置します。一方、今回導入する NFS CSI ドライバは、NFS サーバ上にサブディレクトリを動的に作成し、複数ノードの Pod から同時にマウントできるファイルベースの共有ストレージです。
| 項目 | longhorn-iscsi(第2回) | nfs-csi(今回) |
|---|---|---|
| プロトコル | iSCSI(ブロック) | NFS(ファイル) |
| 管理主体 | Longhorn | csi-driver-nfs |
| レプリカ | 3(ノード間分散) | 1(TrueNAS 上の単一コピー) |
| アクセスモード | RWO / RWX | RWX(複数ノードから同時読み書き) |
| 冗長性 | Longhorn レプリカ | TrueNAS の ZFS(RAIDZ 等)に依存 |
| 主な用途 | VM ディスク、ブロックストレージ | Pod 共有ストレージ、VM ディスク(次回検証) |
前提環境
ハードウェア・仮想化基盤
| 項目 | 値 |
|---|---|
| Proxmox VE | 8.3.0(kernel 6.8.12-4-pve) |
| ホスト IP | 192.168.11.45 |
| CPU | AMD Ryzen 5 5600G(6コア/12スレッド) |
| メモリ | 128 GB |
| ストレージ | local-zfs 約 5.6 TB |
| ネットワーク | vmbr0(192.168.11.0/24) |
Harvester クラスタ
| ノード | VMID | IP | vCPU | メモリ | ディスク |
|---|---|---|---|---|---|
| harvester01 | 131 | 192.168.11.71 | 8 | 16 GB | 400 GB |
| harvester02 | 132 | 192.168.11.72 | 8 | 16 GB | 400 GB |
| harvester03 | 133 | 192.168.11.73 | 8 | 16 GB | 400 GB |
Management VIP: 192.168.11.70、Harvester バージョン: v1.7.1
TrueNAS Scale(NFS サーバ)
| 項目 | 値 |
|---|---|
| VMID | 102(Proxmox 上の VM) |
| IP | 192.168.11.4 |
| NFS 共有パス | /mnt/zpool/pool/NFS |
| データセット容量 | 約 225 GB(quota なし、親プールの空き容量を共有) |
| NFS バージョン | NFSv4 |
TrueNAS 側の NFS 設定(前提条件)
本記事では TrueNAS 側の NFS 共有は設定済みの前提で進めます。以下の設定が完了していることを確認してください。
データセット:
- パス:
/mnt/zpool/pool/NFS - 用途: Harvester クラスタの共有ストレージ
NFS 共有設定(Shares → UNIX (NFS) Shares):
- Path:
/mnt/zpool/pool/NFS - Maproot User:
root - Maproot Group:
wheel - Read Only: オフ
パーミッション:
CSI ドライバが PVC 作成時にサブディレクトリを動的に生成するため、NFS エクスポートディレクトリに書き込み権限が必要です。デフォルトの 755 では CSI コントローラが permission denied になるため、以下のように変更してください。
# TrueNAS のシェルで実行
sudo chmod 777 /mnt/zpool/pool/NFS
# 確認
ls -ld /mnt/zpool/pool/NFS
# 期待する出力: drwxrwxrwx ... /mnt/zpool/pool/NFS
補足: 本環境は自宅ラボのクローズドネットワークのため 777 を設定しています。本番環境では、Authorized Networks の制限や、Mapall User の設定などで適切にアクセス制御を行ってください。
既存の StorageClass
| StorageClass | バックエンド | 用途 |
|---|---|---|
| harvester-longhorn(デフォルト) | 各ノード内蔵ディスク(/dev/sda 400 GB) | VM ディスク(標準) |
| longhorn-iscsi | TrueNAS iSCSI LUN(各 100 GiB × 3) | VM ディスク(iSCSI) |
| nfs-csi(今回作成) | TrueNAS NFS 共有 | Pod 共有ストレージ、VM ディスク(次回検証) |
構成図
補足: csi-driver-nfs のアーキテクチャ
csi-driver-nfs は Controller Pod と Node Pod の 2 種類で構成されますが、NFS の通信を中継するわけではありません。
| Pod | 配置 | 役割 |
|---|---|---|
| csi-nfs-controller | クラスタ内に 1 つ | PVC の作成・削除時に NFS サーバ上のサブディレクトリを作成・削除する管理操作を担当 |
| csi-nfs-node | 各ノードに 1 つ(計 3) | Kubernetes からの指示を受けてノード上で mount -t nfs を実行する仲介役 |
マウントが完了した後のデータ読み書きは、ノードの OS カーネルが NFS クライアントとして TrueNAS に直接通信します。csi-nfs-node Pod はデータ通信を中継しません。
そのため、各コンポーネントが停止した場合の影響は以下の通りです。
| コンポーネント | 停止した場合の影響 |
|---|---|
| csi-nfs-controller | 新規 PVC の作成・削除ができなくなる。既存のマウント済みボリュームへの読み書きは影響なし |
| csi-nfs-node(1台) | そのノード上で新規マウントができなくなる。他ノードは影響なし。既にマウント済みのボリュームは継続動作 |
| TrueNAS(NFS サーバ) | 全ノードから NFS ボリュームにアクセス不可 |
本構成ではシングルポイントは TrueNAS(NFS サーバ)自体ですが、自宅ラボの検証環境のため想定通りです。本番環境では NFS サーバの冗長化(HA 構成や別途バックアップ)を検討してください。
手順
1. Helm の確認
Harvester(RKE2)には Helm が同梱されています。まず Helm が利用可能か確認します。
harvester01:~ # helm version
version.BuildInfo{Version:"v3.19.1", GitCommit:"4f953c223ba21103268e0b664c64240bc69fced7", GitTreeState:"clean", GoVersion:"go1.24.9"}
Helm v3.19.1 が利用可能であることを確認しました。
補足: Helm とは
Helm は Kubernetes のパッケージマネージャです。Linux でいうaptやyumのような役割で、Kubernetes アプリケーション(Chart と呼ばれるパッケージ)のインストール・アップグレード・削除を簡単に行えます。今回は csi-driver-nfs の Chart を Helm でインストールします。
2. csi-driver-nfs のインストール
2.1 Helm リポジトリの追加
csi-driver-nfs の Helm Chart リポジトリを追加し、最新の Chart 情報を取得します。
harvester01:~ # helm repo add csi-driver-nfs https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/master/charts
"csi-driver-nfs" has been added to your repositories
harvester01:~ # helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "csi-driver-nfs" chart repository
Update Complete. ⎈Happy Helming!⎈
2.2 インストールの実行
以下のコマンドで csi-driver-nfs をインストールします。
harvester01:~ # helm install csi-driver-nfs csi-driver-nfs/csi-driver-nfs \
--namespace kube-system \
--set controller.replicas=1
NAME: csi-driver-nfs
LAST DEPLOYED: Fri Mar 13 12:31:57 2026
NAMESPACE: kube-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
The CSI NFS Driver is getting deployed to your cluster.
To check CSI NFS Driver pods status, please run:
kubectl --namespace=kube-system get pods --selector="app.kubernetes.io/instance=csi-driver-nfs" --watch
各オプションの説明は以下の通りです。
| オプション | 説明 |
|---|---|
csi-driver-nfs(第1引数) |
Helm リリース名(任意の名前) |
csi-driver-nfs/csi-driver-nfs(第2引数) |
リポジトリ名/Chart 名 |
--namespace kube-system |
インストール先の Namespace |
--set controller.replicas=1 |
Controller Pod を 1 つに設定(3ノード構成では 1 で十分) |
2.3 Pod の起動確認
harvester01:~ # kubectl --namespace=kube-system get pods \
--selector="app.kubernetes.io/instance=csi-driver-nfs" --watch
NAME READY STATUS RESTARTS AGE
csi-nfs-controller-75dffdcf96-zk7hj 0/5 ContainerCreating 0 15s
csi-nfs-node-2x8jv 0/3 ContainerCreating 0 15s
csi-nfs-node-ljpvp 0/3 ContainerCreating 0 15s
csi-nfs-node-rtvcq 0/3 ContainerCreating 0 15s
csi-nfs-node-rtvcq 3/3 Running 0 18s
csi-nfs-node-ljpvp 3/3 Running 0 18s
csi-nfs-node-2x8jv 3/3 Running 0 18s
csi-nfs-controller-75dffdcf96-zk7hj 5/5 Running 0 23s
約 23 秒で全 Pod が Running になりました。デプロイされた Pod の構成は以下の通りです。
| Pod | 数 | 役割 |
|---|---|---|
| csi-nfs-controller | 1 | PVC の作成・削除時に NFS サーバ上のサブディレクトリを管理 |
| csi-nfs-node | 3(各ノードに 1 つ) | 各ノードで NFS マウントを実行 |
Ctrl+C で watch を終了します。
補足: nfs-subdir-external-provisioner との違い
NFS を Kubernetes で利用する方法として、以前はnfs-subdir-external-provisioner(旧 nfs-client-provisioner)が広く使われていました。これは CSI ドライバではなく External Provisioner として動作し、ノードに CSI コンポーネントをデプロイする必要がないため軽量です。ただし、Kubernetes SIG Storage が公式に推奨しているのは CSI ベースのcsi-driver-nfsであり、新規導入ではこちらを選択するのが望ましいです。
3. StorageClass の作成
NFS CSI ドライバを使用する StorageClass を作成します。
harvester01:~ # kubectl apply -f - << 'EOF'
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-csi
provisioner: nfs.csi.k8s.io
parameters:
server: 192.168.11.4
share: /mnt/zpool/pool/NFS
reclaimPolicy: Delete
volumeBindingMode: Immediate
mountOptions:
- nfsvers=4.1
- hard
- nconnect=8
EOF
storageclass.storage.k8s.io/nfs-csi created
各パラメータの説明は以下の通りです。
| パラメータ | 値 | 説明 |
|---|---|---|
provisioner |
nfs.csi.k8s.io |
csi-driver-nfs のプロビジョナー名 |
parameters.server |
192.168.11.4 |
TrueNAS の IP アドレス |
parameters.share |
/mnt/zpool/pool/NFS |
NFS エクスポートパス |
reclaimPolicy |
Delete |
PVC 削除時にサブディレクトリも自動削除 |
volumeBindingMode |
Immediate |
PVC 作成と同時にプロビジョニング |
nfsvers=4.1 |
— | NFSv4.1 を使用 |
hard |
— | NFS サーバ無応答時にリトライを継続(データ破損防止) |
nconnect=8 |
— | NFS 接続を 8 本並列化しスループットを向上 |
4. 動作テスト
NFS CSI ドライバが正しく機能するか、PVC と Pod を使って検証します。テストの流れは以下の通りです。
- PVC を作成し、CSI ドライバが NFS サーバ上にサブディレクトリを動的に作成することを確認
- harvester01 上の Writer Pod からファイルを書き込み
- harvester02 上の Reader Pod から同じファイルを読み取り、ノード間共有(ReadWriteMany)を確認
- TrueNAS 上で実際のファイルを確認
4.1 テスト PVC の作成
harvester01:~ # kubectl apply -f - << 'EOF'
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test-nfs-pvc
namespace: default
spec:
accessModes:
- ReadWriteMany
storageClassName: nfs-csi
resources:
requests:
storage: 10Gi
EOF
persistentvolumeclaim/test-nfs-pvc created
harvester01:~ # kubectl get pvc test-nfs-pvc -n default
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
test-nfs-pvc Bound pvc-e97d67fe-ab61-40a6-ae87-71f84f984682 10Gi RWX nfs-csi <unset> 10s
STATUS が Bound になり、PVC が正常にプロビジョニングされました。
4.2 Writer Pod の作成(harvester01)
harvester01 上に Pod を作成し、NFS ボリュームにファイルを書き込みます。
harvester01:~ # kubectl apply -f - << 'EOF'
apiVersion: v1
kind: Pod
metadata:
name: test-nfs-writer
namespace: default
spec:
nodeName: harvester01
containers:
- name: writer
image: busybox
command: ["sh", "-c", "echo 'Hello from harvester01' > /data/test.txt && sleep 3600"]
volumeMounts:
- name: nfs-vol
mountPath: /data
volumes:
- name: nfs-vol
persistentVolumeClaim:
claimName: test-nfs-pvc
EOF
pod/test-nfs-writer created
harvester01:~ # kubectl get pod test-nfs-writer -n default
NAME READY STATUS RESTARTS AGE
test-nfs-writer 1/1 Running 0 9s
Pod が Running になり、/data/test.txt に「Hello from harvester01」が書き込まれました。
4.3 Reader Pod の作成(harvester02)
別のノード harvester02 上に Pod を作成し、同じ PVC をマウントして書き込まれたファイルを読み取ります。
harvester01:~ # kubectl apply -f - << 'EOF'
apiVersion: v1
kind: Pod
metadata:
name: test-nfs-reader
namespace: default
spec:
nodeName: harvester02
containers:
- name: reader
image: busybox
command: ["sh", "-c", "cat /data/test.txt && sleep 3600"]
volumeMounts:
- name: nfs-vol
mountPath: /data
volumes:
- name: nfs-vol
persistentVolumeClaim:
claimName: test-nfs-pvc
EOF
pod/test-nfs-reader created
harvester01:~ # kubectl get pod test-nfs-reader -n default
NAME READY STATUS RESTARTS AGE
test-nfs-reader 1/1 Running 0 8s
harvester01:~ # kubectl logs test-nfs-reader -n default
Hello from harvester01
harvester01 で書き込んだデータを harvester02 から正常に読み取れました。これにより、NFS CSI による ReadWriteMany(複数ノードからの同時読み書き)が機能していることが確認できました。
4.4 TrueNAS 上のファイル確認
TrueNAS のシェルで、CSI ドライバが作成したサブディレクトリと書き込まれたファイルを確認します。
root@truenas:~ # ls -la /mnt/zpool/pool/NFS/
total 7
drwxrwxrwx 3 root root 3 Mar 13 13:32 .
drwxr-xr-x 6 root root 8 Mar 8 14:34 ..
drwxrwxrwx 2 root root 3 Mar 13 13:34 pvc-e97d67fe-ab61-40a6-ae87-71f84f984682
root@truenas:~ # ls -la /mnt/zpool/pool/NFS/pvc-e97d67fe-ab61-40a6-ae87-71f84f984682/
total 5
drwxrwxrwx 2 root root 3 Mar 13 13:34 .
drwxrwxrwx 3 root root 3 Mar 13 13:32 ..
-rw-r--r-- 1 root root 23 Mar 13 13:34 test.txt
CSI ドライバが PVC 名と同じ名前のサブディレクトリ(pvc-e97d67fe-...)を自動作成し、その中に Writer Pod が書き込んだ test.txt が格納されていることを確認できました。
5. クリーンアップ
テストリソースを削除します。
harvester01:~ # kubectl delete pod test-nfs-writer test-nfs-reader -n default
pod "test-nfs-writer" deleted
pod "test-nfs-reader" deleted
harvester01:~ # kubectl delete pvc test-nfs-pvc -n default
persistentvolumeclaim "test-nfs-pvc" deleted
リソースが削除されたことを確認します。
harvester01:~ # kubectl get pod,pvc -n default
No resources found in default namespace.
TrueNAS 側でもサブディレクトリが自動削除されたことを確認します。
root@truenas:~ # ls -la /mnt/zpool/pool/NFS/
total 4
drwxrwxrwx 2 root root 2 Mar 13 13:45 .
drwxr-xr-x 6 root root 8 Mar 8 14:34 ..
StorageClass の reclaimPolicy: Delete により、PVC を削除するとサブディレクトリも自動的に削除されました。
トラブルシューティング
PVC が Pending のまま Bound にならない
PVC 作成後にステータスが Pending のまま変わらない場合は、以下を確認してください。
kubectl describe pvc <pvc名> -n default
Events に permission denied と表示される場合は、TrueNAS 側の NFS エクスポートディレクトリのパーミッションが不足しています。TrueNAS のシェルで以下を実行してください。
sudo chmod 777 /mnt/zpool/pool/NFS
CSI ドライバの Controller Pod が PVC 作成時に NFS 共有上にサブディレクトリを mkdir しますが、エクスポートディレクトリが 755(デフォルト)の場合、書き込み権限がないためプロビジョニングが失敗します。
CSI ドライバの Pod が起動しない
kubectl --namespace=kube-system get pods --selector="app.kubernetes.io/instance=csi-driver-nfs"
kubectl --namespace=kube-system describe pod <pod名>
ImagePullBackOff が出る場合は、Harvester ノードからインターネットへの疎通を確認してください。
補足: csi-nfs-node Pod が停止しても、そのノード上で既にマウント済みのボリュームへの読み書きには影響しません。NFS のデータ通信はノードの OS カーネルが直接行うためです。影響を受けるのは、そのノード上での新規マウント操作のみです。
NFS サーバへの接続確認
各 Harvester ノードから NFS サーバに接続できるか確認するには、以下を実行します。
# NFS ポートへの疎通確認
nc -zv 192.168.11.4 2049
# NFS エクスポート一覧の確認
showmount -e 192.168.11.4
まとめ
本記事では、Harvester クラスタに NFS CSI ドライバ(csi-driver-nfs)を導入し、TrueNAS Scale の NFS 共有を Kubernetes の共有ストレージとして利用できるようにしました。
実施した作業を振り返ります。
| ステップ | 内容 | 結果 |
|---|---|---|
| Helm 確認 | Harvester 同梱の Helm v3.19.1 を確認 | OK |
| csi-driver-nfs インストール | Helm Chart でデプロイ(Controller×1、Node×3) | 全 Pod Running |
| StorageClass 作成 |
nfs-csi(NFSv4.1、reclaimPolicy: Delete) |
作成完了 |
| 動作テスト | PVC 作成 → Writer/Reader Pod で RWX 確認 | ノード間共有成功 |
| クリーンアップ | Pod・PVC 削除、サブディレクトリ自動削除確認 | 正常削除 |
現在の Harvester クラスタには、以下の 3 つの StorageClass が利用可能です。
| StorageClass | バックエンド | レプリカ | 主な用途 |
|---|---|---|---|
| harvester-longhorn | ノード内蔵ディスク | 3 | VM ディスク(標準) |
| longhorn-iscsi | TrueNAS iSCSI LUN | 3 | VM ディスク(iSCSI) |
| nfs-csi | TrueNAS NFS 共有 | 1 | Pod 共有ストレージ、VM ディスク(次回検証) |
次回予告
次回は、NFS および iSCSI の StorageClass を使って実際に仮想マシンのデータストアとして利用できるか検証します。Harvester の Image 登録時に StorageClass を指定することで、VM のブートディスクを NFS や iSCSI LUN 上に配置できることを確認する予定です。