はじめに
本記事は、自宅ラボで SUSE Harvester(HCI)を構築・拡張するシリーズの第4回です。
| 回 | 内容 | 記事リンク |
|---|---|---|
| 第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 ドライバを導入し共有ストレージを構成 | SUSE Harvester に NFS CSI ドライバを導入して共有ストレージを構成する |
| 第4回 | 3 種類のデータストアで VM を起動し比較(本記事) | — |
第1回〜第3回で、Harvester クラスタに 3 種類の StorageClass を構成しました。今回はそれぞれの StorageClass を VM のデータストアとして使用し、実際に仮想マシンを起動して、ディスクイメージがどこに・どのような仕組みで格納されるかを実機で確認・比較します。
特に、Longhorn ベースの StorageClass(harvester-longhorn、longhorn-iscsi)と外部 CSI ドライバ(nfs-csi)では、OS イメージの管理方式が根本的に異なります。この違いについても掘り下げて解説します。
前提環境
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
| 項目 | 値 |
|---|---|
| IP | 192.168.11.4 |
| iSCSI LUN | lun1〜lun3(各 100 GiB、各ノードにパススルー) |
| NFS 共有 | /mnt/zpool/pool/NFS(約 225 GB) |
StorageClass 一覧
| StorageClass | バックエンド | 構築記事 |
|---|---|---|
| harvester-longhorn(デフォルト) | 各ノード内蔵ディスク(400 GB) | 第1回 |
| longhorn-iscsi | TrueNAS iSCSI LUN(各 100 GiB × 3) | 第2回 |
| nfs-csi | TrueNAS NFS 共有(約 225 GB) | 第3回 |
構成図
手順
1. OS イメージの登録
Harvester では VM を作成する際に、OS イメージを事前に登録する必要があります。イメージ登録時に StorageClass を指定することで、そのイメージから作成される VM のディスクが指定した StorageClass 上に配置されます。
今回は軽量な openSUSE Leap 15.6 の Cloud イメージ(約 270 MB)を使用します。3 種類の StorageClass それぞれにイメージを登録します。
1.1 harvester-longhorn 用イメージの登録
Harvester UI(https://192.168.11.70)で以下の操作を行います。
- 左メニュー → Images → Create
-
Basics タブ:
- Namespace: default
- Name:
openSUSE-Leap-15.6 - Type: URL
- URL:
https://download.opensuse.org/distribution/leap/15.6/appliances/openSUSE-Leap-15.6-Minimal-VM.x86_64-Cloud.qcow2
-
Storage タブ:
- Storage Class: harvester-longhorn (Default)
- Create をクリック
Images 一覧でステータスが Active になるまで待ちます。
1.2 longhorn-iscsi 用イメージの登録
同様の手順で、StorageClass を変更して登録します。
- 左メニュー → Images → Create
-
Basics タブ:
- Name:
openSUSE-Leap-15.6-iscsi - Type: URL
- URL: (上記と同じ)
- Name:
-
Storage タブ:
- Storage Class: longhorn-iscsi
- Create をクリック
1.3 nfs-csi 用イメージの登録
- 左メニュー → Images → Create
-
Basics タブ:
- Name:
openSUSE-Leap-15.6-nfs - Type: URL
- URL: (上記と同じ)
- Name:
-
Storage タブ:
- Storage Class: nfs-csi
- Create をクリック
1.4 登録結果の確認
3 つのイメージがすべて Active になったことを確認します。
| イメージ名 | StorageClass | サイズ | ステータス |
|---|---|---|---|
| openSUSE-Leap-15.6 | harvester-longhorn | 264 Mi | Active |
| openSUSE-Leap-15.6-iscsi | longhorn-iscsi | 264 Mi | Active |
| openSUSE-Leap-15.6-nfs | nfs-csi | 264 Mi | Active |
2. VM の作成と起動確認
各 StorageClass のイメージから VM を 1 台ずつ作成します。1 台目は詳細に解説し、2 台目・3 台目は差分のみ記載します。
2.1 test-longhorn-vm の作成(harvester-longhorn)
- 左メニュー → Virtual Machines → Create
-
Basics タブ:
- Namespace: default
- Name:
test-longhorn-vm - CPU: 1
- Memory: 2 GiB
-
Volumes タブ:
- Image: openSUSE-Leap-15.6 (harvester-longhorn) を選択
- Size: 10 GiB
- Networks 以降はデフォルトのまま
- Create をクリック
VM 一覧で test-longhorn-vm のステータスが Running になることを確認します。
NAME STATUS CPU MEMORY IP NODE AGE
test-longhorn-vm Running 1 2 Gi 10.52.x.xx harvester01 xxs
2.2 test-iscsi-vm の作成(longhorn-iscsi)
手順は 2.1 と同様です。以下の項目のみ変更します。
| 項目 | 値 |
|---|---|
| Name | test-iscsi-vm |
| Image | openSUSE-Leap-15.6-iscsi (longhorn-iscsi) |
VM 一覧で Running になることを確認します。
NAME STATUS CPU MEMORY IP NODE AGE
test-iscsi-vm Running 1 2 Gi 10.52.x.xx harvester03 xxs
2.3 test-nfs-vm の作成(nfs-csi)
同様に以下の項目を変更して作成します。
| 項目 | 値 |
|---|---|
| Name | test-nfs-vm |
| Image | openSUSE-Leap-15.6-nfs (nfs-csi) |
VM 一覧で Running になることを確認します。
NAME STATUS CPU MEMORY IP NODE AGE
test-nfs-vm Running 1 2 Gi 10.52.x.xx harvester01 xxs
2.4 全 VM の起動確認
3 台すべてが Running であることを確認します。
NAME STATUS CPU MEMORY NODE
test-longhorn-vm Running 1 2 Gi harvester01
test-iscsi-vm Running 1 2 Gi harvester03
test-nfs-vm Running 1 2 Gi harvester01
3 種類の StorageClass すべてで VM が正常に起動しました。
3. ディスク格納先の確認
VM が正常に起動したところで、各 StorageClass でディスクイメージが実際にどこに格納されているかを確認します。
3.1 PVC の確認
まず、各 VM に紐づく PVC を確認します。
harvester01:~ # kubectl get pvc -n default -o custom-columns=NAME:.metadata.name,VOLUME:.spec.volumeName,STORAGECLASS:.spec.storageClassName,CAPACITY:.status.capacity.storage
NAME VOLUME STORAGECLASS CAPACITY
image-xl5hb pvc-be9eb4a4-d648-4dc9-a9ff-55c7442c6bd2 nfs-csi 928738743
test-iscsi-vm-disk-0-ivit5 pvc-a873f384-bb51-41dd-95e4-617f086a4451 longhorn-image-dsnm9 10Gi
test-longhorn-vm-disk-0-eudee pvc-b03e2931-8839-4c1d-a73f-5b317e64d8d2 longhorn-image-hjpz6 10Gi
test-nfs-vm-disk-0-ah3ap pvc-3f9db7a1-a3cf-41d2-8784-38b0b3cd7a23 nfs-csi 11362347344
ここで注目すべき点が 2 つあります。
1つ目は、Longhorn ベースの VM ディスク(test-iscsi-vm、test-longhorn-vm)の StorageClass が、元の harvester-longhorn や longhorn-iscsi ではなく、longhorn-image-dsnm9 や longhorn-image-hjpz6 という自動生成された名前になっていることです。これは後述する「Backing Image」の仕組みに関係します。
2つ目は、nfs-csi の PVC が 2 つ(image-xl5hb と test-nfs-vm-disk-0-ah3ap)存在していることです。Longhorn ベースの方には image- で始まる PVC がありません。この違いも後述します。
3.2 harvester-longhorn のディスク格納先
Longhorn のレプリカがどのノードに配置されているかを確認します。
harvester01:~ # kubectl -n longhorn-system get replicas.longhorn.io \
-l longhornvolume=pvc-b03e2931-8839-4c1d-a73f-5b317e64d8d2 \
-o custom-columns=NAME:.metadata.name,NODE:.spec.nodeID,DISK:.spec.diskPath,STATE:.status.currentState
NAME NODE DISK STATE
pvc-b03e2931-xxxx-r-605c4409 harvester01 /var/lib/harvester/defaultdisk running
pvc-b03e2931-xxxx-r-62d524a3 harvester02 /var/lib/harvester/defaultdisk running
pvc-b03e2931-xxxx-r-6e93d12d harvester03 /var/lib/harvester/defaultdisk running
3 つのレプリカが harvester01〜03 の /var/lib/harvester/defaultdisk(ノード内蔵ディスク)に分散配置されています。
実際のファイルを harvester01 上で確認します。
harvester01:~ # ls -lh /var/lib/harvester/defaultdisk/replicas/pvc-b03e2931-8839-4c1d-a73f-5b317e64d8d2-xxxxxxxx/
-rw-r--r-- 1 root root 10G Mar 13 14:03 volume-head-000.img
-rw-r--r-- 1 root root xxx Mar 13 14:03 volume-head-000.img.meta
...
volume-head-000.img(10 GB)がレプリカのディスクイメージファイルです。これが各ノードに 1 つずつ、合計 3 つ存在します。
3.3 longhorn-iscsi のディスク格納先
harvester01:~ # kubectl -n longhorn-system get replicas.longhorn.io \
-l longhornvolume=pvc-a873f384-bb51-41dd-95e4-617f086a4451 \
-o custom-columns=NAME:.metadata.name,NODE:.spec.nodeID,DISK:.spec.diskPath,STATE:.status.currentState
NAME NODE DISK STATE
pvc-a873f384-xxxx-r-084daeb5 harvester03 /var/lib/harvester/extra-disks/iscsi-lun3 running
pvc-a873f384-xxxx-r-408296f0 harvester01 /var/lib/harvester/extra-disks/iscsi-lun1 running
pvc-a873f384-xxxx-r-98a669ad harvester02 /var/lib/harvester/extra-disks/iscsi-lun2 running
harvester-longhorn との違いとして、DISK 列が /var/lib/harvester/extra-disks/iscsi-lunX になっています。これは第2回で登録した TrueNAS の iSCSI LUN です。レプリカは 3 つで、各ノードの iSCSI LUN に 1 つずつ分散配置されています。
StorageClass longhorn-iscsi に diskSelector: "iscsi" を設定しているため、Longhorn はタグ iscsi が付いたディスク(iSCSI LUN)にのみレプリカを配置します。
3.4 nfs-csi のディスク格納先
nfs-csi は Longhorn ではなく NFS CSI ドライバが管理するため、レプリカの概念がありません。ディスクイメージは TrueNAS の NFS 共有上に直接格納されます。
TrueNAS のシェルで確認します。
root@truenas:~ # ls -la /mnt/zpool/pool/NFS/
drwxrwxrwx 2 root root 3 Mar 13 13:34 pvc-be9eb4a4-d648-4dc9-a9ff-55c7442c6bd2
drwxrwxrwx 2 root root 3 Mar 13 14:20 pvc-3f9db7a1-a3cf-41d2-8784-38b0b3cd7a23
Longhorn ベースの方ではノード上に VM ディスクの PVC ディレクトリだけが見えていましたが、NFS では 2 つのサブディレクトリ が存在しています。これは 3.1 節で確認した nfs-csi の PVC 2 つに対応しています。
| サブディレクトリ | 対応する PVC | 中身 | 用途 |
|---|---|---|---|
| pvc-be9eb4a4-... | image-xl5hb | OS イメージ(URL からダウンロードした qcow2) | Image 登録時に作成されたマスターイメージ |
| pvc-3f9db7a1-... | test-nfs-vm-disk-0-ah3ap | disk.img(10 GB) | VM 作成時にマスターイメージからコピーされたブートディスク |
VM のブートディスクの中身を確認します。
root@truenas:~ # ls -lh /mnt/zpool/pool/NFS/pvc-3f9db7a1-a3cf-41d2-8784-38b0b3cd7a23/
-rw-r--r-- 1 root root 10G Mar 13 14:20 disk.img
disk.img(10 GB)が VM のブートディスクです。Longhorn の volume-head-000.img と異なり、TrueNAS 上に 1 つだけ格納されています。
4. OS イメージの管理方式の違い — Backing Image と PVC
3.1 節と 3.4 節で確認した「Longhorn には Image 用 PVC がないのに NFS にはある」という違いについて、深掘りします。これは Longhorn ベースと NFS CSI で OS イメージの管理方式が根本的に異なるためです。
4.1 Longhorn の Backing Image とは
Harvester が Longhorn ベースの StorageClass に OS イメージを登録すると、Longhorn は Backing Image という専用の仕組みでイメージを管理します。Backing Image は通常の PVC(Persistent Volume Claim)としては存在せず、Longhorn 内部のリソースとして各ノードのディスクにキャッシュされます。
VM を作成すると、Longhorn はこの Backing Image を「ベース」として Copy-on-Write(CoW) 方式で差分ディスクを作成します。つまり、OS イメージ部分は共有したまま、VM が書き込んだ変更分だけを volume-head-000.img に記録します。
この仕組みの違いにより、同じ OS イメージから複数の VM を作成した場合に大きな差が出ます。Longhorn では Backing Image を共有するため追加の容量消費は差分のみですが、NFS では VM ごとにイメージ全体がコピーされます。
4.2 自動生成される StorageClass
Harvester は Image 登録時に、Longhorn ベースの場合は Backing Image を参照するための専用 StorageClass を自動生成します。
harvester01:~ # kubectl get virtualmachineimages.harvesterhci.io -n default \
-o custom-columns=NAME:.metadata.name,DISPLAY:.spec.displayName,STORAGECLASS:.status.storageClassName
NAME DISPLAY STORAGECLASS
image-dsnm9 openSUSE-Leap-15.6-iscsi longhorn-image-dsnm9
image-hjpz6 openSUSE-Leap-15.6 longhorn-image-hjpz6
image-xl5hb openSUSE-Leap-15.6-nfs nfs-csi
Longhorn ベースのイメージには longhorn-image-xxxxx という自動生成 StorageClass が割り当てられています。この StorageClass の中身を確認すると、backingImage パラメータが含まれています。
harvester01:~ # kubectl get storageclass longhorn-image-hjpz6 -o yaml | head -20
allowVolumeExpansion: true
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: longhorn-image-hjpz6
parameters:
backingImage: vmi-f198721d-1295-4672-abe2-40dc768ab81c
migratable: "true"
numberOfReplicas: "3"
staleReplicaTimeout: "30"
provisioner: driver.longhorn.io
reclaimPolicy: Delete
volumeBindingMode: Immediate
harvester01:~ # kubectl get storageclass longhorn-image-dsnm9 -o yaml | head -20
allowVolumeExpansion: true
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: longhorn-image-dsnm9
parameters:
backingImage: vmi-bbc61d48-7cfe-49af-a4a0-a0a96421b4aa
diskSelector: iscsi
migratable: "true"
numberOfReplicas: "3"
staleReplicaTimeout: "30"
provisioner: driver.longhorn.io
reclaimPolicy: Delete
volumeBindingMode: Immediate
backingImage パラメータが Backing Image リソースの名前を指しています。また longhorn-image-dsnm9 には diskSelector: iscsi が引き継がれており、元の longhorn-iscsi の設定が反映されていることが分かります。
一方、nfs-csi のイメージには自動生成 StorageClass はなく、nfs-csi がそのまま使われています。外部 CSI ドライバには Backing Image の仕組みがないため、Harvester はイメージを通常の PVC として格納します。
4.3 Backing Image の一覧確認
Longhorn に登録されている Backing Image は以下のコマンドで確認できます。
harvester01:~ # kubectl -n longhorn-system get backingimages.longhorn.io
NAME UUID SOURCETYPE SIZE VIRTUALSIZE AGE
vmi-bbc61d48-7cfe-49af-a4a0-a0a96421b4aa a6ca020e download 276698112 877658112 37m
vmi-f198721d-1295-4672-abe2-40dc768ab81c 63e75209 download 276698112 877658112 62m
どの Backing Image がどの Harvester Image に対応するかは、以下のコマンドで確認できます。
harvester01:~ # kubectl -n longhorn-system get backingimages.longhorn.io \
-o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.metadata.annotations.harvesterhci\.io/imageId}{"\t"}{.status.size}{"\n"}{end}'
vmi-bbc61d48-7cfe-49af-a4a0-a0a96421b4aa default/image-dsnm9 276698112
vmi-f198721d-1295-4672-abe2-40dc768ab81c default/image-hjpz6 276698112
| Backing Image | Harvester Image | 対応する Image 名 | サイズ |
|---|---|---|---|
| vmi-bbc61d48-... | default/image-dsnm9 | openSUSE-Leap-15.6-iscsi (longhorn-iscsi) | 約 264 MB |
| vmi-f198721d-... | default/image-hjpz6 | openSUSE-Leap-15.6 (harvester-longhorn) | 約 264 MB |
nfs-csi の openSUSE-Leap-15.6-nfs は Backing Image が存在せず、通常の PVC(image-xl5hb)として管理されています。
4.4 Image 管理方式のまとめ
| 項目 | Longhorn ベース(harvester-longhorn / longhorn-iscsi) | nfs-csi |
|---|---|---|
| OS イメージの管理方式 | Backing Image(Longhorn 内部リソース) | 通常の PVC |
| Image 用 PVC の有無 | なし(PVC としては見えない) | あり(image-xl5hb) |
| VM ディスクの作成方式 | Copy-on-Write(差分のみ記録) | イメージ全体をコピー |
| 自動生成 StorageClass | あり(longhorn-image-xxxxx) | なし(nfs-csi をそのまま使用) |
| 同一イメージから VM 2 台作成時の追加消費 | 差分のみ(小さい) | イメージ全体 × 2(大きい) |
5. ディスク格納先のまとめ
3 種類の StorageClass における VM ディスクの格納先を図で整理します。
3 方式の比較
| 項目 | harvester-longhorn | longhorn-iscsi | nfs-csi |
|---|---|---|---|
| バックエンド | ノード内蔵ディスク | TrueNAS iSCSI LUN | TrueNAS NFS 共有 |
| プロトコル | ローカルディスクアクセス | iSCSI(ブロック) | NFS(ファイル) |
| 管理主体 | Longhorn | Longhorn | csi-driver-nfs |
| OS イメージ管理 | Backing Image(CoW) | Backing Image(CoW) | 通常の PVC(フルコピー) |
| レプリカ数 | 3(ノード間分散) | 3(iSCSI LUN 間分散) | 1(TrueNAS 上の単一コピー) |
| 10 GB VM の実消費容量 | 30 GB(10 GB × 3 ノード) | 30 GB(10 GB × 3 LUN) | 10 GB + OS イメージ分 |
| 冗長性 | ノード 1 台故障でもデータ保持 | ノード 1 台故障でもデータ保持(ただし LUN は TrueNAS に依存) | TrueNAS の ZFS 冗長性に依存 |
| シングルポイント | なし(3 レプリカ分散) | TrueNAS(iSCSI ターゲット) | TrueNAS(NFS サーバ) |
| 容量効率(VM 1 台) | 低(3 倍消費) | 低(3 倍消費) | 高(1 倍 + イメージ分) |
| 容量効率(同一イメージ複数 VM) | CoW により差分のみ追加 | CoW により差分のみ追加 | VM ごとにフルコピー |
| ディスクイメージ形式 | volume-head-000.img | volume-head-000.img | disk.img |
| パフォーマンス(想定・未測定) | 高速(ローカルディスク直接アクセス) | 中程度(ネットワーク経由 iSCSI) | 中程度(ネットワーク経由 NFS) |
注: パフォーマンスの行は実測値ではなく、アーキテクチャに基づく想定です。ローカルディスクアクセスはネットワークを介さないため最も高速と考えられますが、iSCSI と NFS の実際の差異はネットワーク帯域やストレージ構成に依存します。正確な比較にはベンチマーク測定が必要です。
トラブルシューティング
Image 登録時に StorageClass が表示されない
Images → Create の Storage タブ に目的の StorageClass が表示されない場合は、StorageClass が正しく作成されているか確認してください。
kubectl get storageclass
longhorn-iscsi や nfs-csi が一覧に表示されていれば、Image 作成画面のドロップダウンにも表示されます。
nfs-csi の Image が Active にならない
NFS 共有のパーミッションを確認してください。CSI ドライバがサブディレクトリを作成できない場合、Image のダウンロードが失敗します。
# TrueNAS のシェルで確認
ls -ld /mnt/zpool/pool/NFS
# drwxrwxrwx であること
詳細は第3回記事のトラブルシューティングを参照してください。
VM が Starting のまま Running にならない
VM の Events を確認します。
kubectl get events -n default --sort-by='.lastTimestamp' | grep <vm名>
PVC が Bound にならない場合は、対応する StorageClass のバックエンドストレージ(Longhorn ディスクや NFS サーバ)の空き容量を確認してください。
まとめ
本記事では、Harvester クラスタに構成した 3 種類の StorageClass(harvester-longhorn、longhorn-iscsi、nfs-csi)それぞれで VM を作成・起動し、ディスクイメージの格納先と OS イメージの管理方式を実機で確認しました。
| VM 名 | StorageClass | ディスク格納先 | レプリカ | Image 管理 | 起動結果 |
|---|---|---|---|---|---|
| test-longhorn-vm | harvester-longhorn | 各ノード /var/lib/harvester/defaultdisk/replicas/
|
3 | Backing Image(CoW) | Running |
| test-iscsi-vm | longhorn-iscsi | 各ノード /var/lib/harvester/extra-disks/iscsi-lunX/
|
3 | Backing Image(CoW) | Running |
| test-nfs-vm | nfs-csi | TrueNAS /mnt/zpool/pool/NFS/pvc-xxxx/
|
1 | 通常 PVC(フルコピー) | Running |
3 方式すべてで VM のブートディスクとして利用できることが確認できました。Longhorn ベースの 2 方式は Backing Image による効率的な Copy-on-Write を活用できますが、容量は 3 倍消費します。nfs-csi は容量効率が高いものの、VM ごとにフルコピーが作成され、TrueNAS がシングルポイントとなります。用途や要件に応じて使い分けることが可能です。
次回予告
次回は、3 種類のデータストアにおける VM のディスク I/O パフォーマンスをベンチマーク測定し、定量的に比較する予定です。