はじめに
概要
私は、研究室にあるベアメタルサーバーを複数台用いてKubernetesクラスタを構築しています。
参考:
本クラスタはこれまで、各ノードのローカルディスクを個別に利用しており、ノード障害時に永続データが失われるリスクがありました。
そこで、今回は本クラスタに分散ストレージを導入するために、軽量な分散ブロックストレージシステムであるLonghorn をインストールし、動作確認を行いました。
なぜ分散ストレージが必要か
ノード障害によるデータ損失リスク
分散ストレージ導入前のクラスタには、PVCとして管理されるアプリケーションの永続データを保存するにあたり、以下2点の課題がありました。
1点目は、従来の構成では、各ノードがローカルディスク上にデータを保持していたため、ノードが停止するとそのデータにアクセスできなくなってしまうという点です。
2点目は、Podが別ノードに再スケジューリングされても、同じデータを引き継ぐことができず、永続性が保証されないという問題です。
これらの課題を解消するために、分散ストレージシステムの一つである、Longhornを導入しました。
Longhornについて
Longhorn は、Kubernetes 環境向けに設計された軽量で信頼性が高く、高性能な分散型ブロックストレージシステムです。
簡単に、アーキテクチャを確認します。
Kubernetesは CSI API により、LonghornのCSI Plugin と通信し PVC 作成や削除、アタッチ/デタッチなどの操作をLonghornに伝達します。
DaemonSetとして動作する Longhorn Manager は、Longhorn UIまたはLonghorn CSI PluginからのAPIリクエストを処理します。
Longhorn Manager にボリューム作成を指示すると、指定されたノード上に Longhorn Engine インスタンスが作成されます。
Longhorn Engine は、データの読み書きを行い、可用性を上げるため、複数の Replica に対してデータをレプリケーションします。
Longhorn UI は、Longhorn API を利用してクラスタ内の Volume 状態を可視化する Web インターフェースです。後に確認したいと思います。

(図は https://longhorn.io/docs/1.10.0/concepts/ より引用)
Longhornの構築
Longhorn導入前にあたり必要な設定
ツールのインストール
以下ページを参考に、open-iscsiの導入、専用ディスクの作成とマウントなど、Longhornを動かすための前提を整理します。
open-iscsi と NFSクライアント、デバイスマッパーのインストール
apt-get install -y open-iscsi nfs-common dmsetup
専用ディスクの作成とマウント設定
Longhornはデフォルトで各ノードの /var/lib/longhorn/ をディスクパスとして利用します。
ここではシステムディスクと分離するため、新しいディスク /dev/sdb を /var/lib/longhorn-data にマウントし、UI上でこのパスをLonghornのディスクとして登録しました。
今回は、VirtualBoxを利用しVMを作成しKubernetes Nodeとしているため、以下のように10GBの新しい仮想ハードディスクファイルを接続します。
# worker-1
VBoxManage createhd --filename worker1-longhorn.vdi --size 10240
VBoxManage storageattach "k8s-worker-1" --storagectl "SATA Controller" --port 2 --device 0 --type hdd --medium worker1-longhorn.vdi
# worker-2
VBoxManage createhd --filename worker2-longhorn.vdi --size 10240
VBoxManage storageattach "k8s-worker-2" --storagectl "SATA Controller" --port 2 --device 0 --type hdd --medium worker2-longhorn.vdi
# worker-3
VBoxManage createhd --filename worker3-longhorn.vdi --size 10240
VBoxManage storageattach "k8s-worker-3" --storagectl "SATA Controller" --port 2 --device 0 --type hdd --medium worker3-longhorn.vdi
OSは、元々あったディスクを /dev/sda (サイズ約30GB) として認識しており、それに加えて、/dev/sdb という名前で、サイズが 10GB の新しいディスクを認識しています。
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 8:0 0 29.3G 0 disk
├─sda1 8:1 0 1M 0 part
├─sda2 8:2 0 2G 0 part /boot
└─sda3 8:3 0 27.3G 0 part
└─ubuntu--vg-ubuntu--lv 253:0 0 13.6G 0 lvm /
sdb 8:16 0 10G 0 disk
新しいディスク(/dev/sdb)を ext4 でフォーマットし、/var/lib/longhorn-data をLonghornがデフォルトでデータを保存する領域として使用するディレクトリとして作成します。そして、フォーマットした /dev/sdb をマウントします。
最後に、OSを再起動してもこのマウント設定が保持されるよう、/etc/fstab に設定を追記します。
sudo mkfs.ext4 /dev/sdb
sudo mkdir -p /var/lib/longhorn-data
sudo mount /dev/sdb /var/lib/longhorn-data
UUID=$(sudo blkid -s UUID -o value /dev/sdb)
echo "UUID=$UUID /var/lib/longhorn-data ext4 defaults,nofail 0 0" | sudo tee -a /etc/fstab
10GBのディスク(/dev/sdb)が /var/lib/longhorn-data に正しくマウントされ、Longhornがデータ保存に使える状態になっていることを確認します。
$ df -h
Filesystem Size Used Avail Use% Mounted on
tmpfs 297M 1.4M 296M 1% /run
/dev/mapper/ubuntu--vg-ubuntu--lv 14G 8.6G 4.2G 68% /
/dev/sdb 9.8G 24K 9.3G 1% /var/lib/longhorn-data
ディスク容量の拡張
後述のLonghornデプロイ時に、Node上のディスク容量が不足し、複数のPodがEvictedとなる事態が発生しました。
/var/lib/longhorn はルートファイルシステム上にマウントされており、その使用率が 83% に達していることが根本的な原因でした。
$ df -h /var/lib/longhorn
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/ubuntu--vg-ubuntu--lv 14G 11G 2.2G 83% /
次に、ディスクとLVMの構成を確認しました。
物理ディスク sda のパーティションである sda3 の27.3Gから ubuntu--vg-ubuntu--lv の13.6Gを引いた13.7Gは、ボリュームグループ(VG)内の未割り当て領域です。
$ lsblk -o NAME,SIZE,FSTYPE,TYPE,MOUNTPOINTS
NAME SIZE FSTYPE TYPE MOUNTPOINTS
sda 29.3G disk
├─sda1 1M part
├─sda2 2G ext4 part /boot
└─sda3 27.3G LVM2_member part
└─ubuntu--vg-ubuntu--lv 13.6G ext4 lvm /
sdb 10G ext4 disk /var/lib/longhorn-data
$ sudo pvs; sudo vgs; sudo lvs
PV VG Fmt Attr PSize PFree
/dev/sda3 ubuntu-vg lvm2 a-- 27.29g <13.65g
VG #PV #LV #SN Attr VSize VFree
ubuntu-vg 1 1 0 wz--n- 27.29g <13.65g
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
ubuntu-lv ubuntu-vg -wi-ao---- 13.64g
このVG内の未割り当て領域(約13.6G)をすべて既存のLV ubuntu-lv に割り当て、ディスク容量を拡張します。
$ sudo lvextend -r -l +100%FREE /dev/ubuntu-vg/ubuntu-lv
Size of logical volume ubuntu-vg/ubuntu-lv changed from 13.64 GiB (3493 extents) to 27.29 GiB (6987 extents).
Logical volume ubuntu-vg/ubuntu-lv successfully resized.
resize2fs 1.46.5 (30-Dec-2021)
Filesystem at /dev/mapper/ubuntu--vg-ubuntu--lv is mounted on /; on-line resizing required
old_desc_blocks = 2, new_desc_blocks = 4
The filesystem on /dev/mapper/ubuntu--vg-ubuntu--lv is now 7154688 (4k) blocks long.
実行後、ルートファイルシステムで利用可能なディスクサイズが13G増えたことを確認しました。
$ df -h /
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/ubuntu--vg-ubuntu--lv 27G 7.7G 18G 30% /
Longhornのインストール
様々なインストール方法があります。
今回はkubectlでインストールしました。
kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/v1.10.0/deploy/longhorn.yaml
ディスクの容量を十分に確保した状態で、Longhornのコンポーネントが正常にRunningになるまで待ちます。
ryu@k8s-master:~$ k get pods -n longhorn-system
NAME READY STATUS RESTARTS AGE
csi-attacher-699d7b6777-2slns 1/1 Running 1 (3m33s ago) 5m6s
csi-attacher-699d7b6777-b2f4q 1/1 Running 3 (2m23s ago) 5m6s
csi-attacher-699d7b6777-fdfjn 1/1 Running 2 (79s ago) 5m6s
csi-provisioner-84bbd9588b-d8gh6 1/1 Running 2 (2m57s ago) 5m6s
csi-provisioner-84bbd9588b-lzf5g 1/1 Running 2 (58s ago) 5m6s
csi-provisioner-84bbd9588b-pr88z 1/1 Running 1 (3m24s ago) 5m6s
csi-resizer-7878697556-4rth9 1/1 Running 0 5m5s
csi-resizer-7878697556-9rgvn 1/1 Running 2 (2m49s ago) 5m5s
csi-resizer-7878697556-mz5kl 1/1 Running 2 (37s ago) 5m5s
csi-snapshotter-765dc584c4-f6vkq 1/1 Running 0 5m4s
csi-snapshotter-765dc584c4-sp9p5 1/1 Running 1 (54s ago) 5m4s
csi-snapshotter-765dc584c4-znvlc 1/1 Running 2 (2m38s ago) 5m5s
engine-image-ei-26bab25d-2sp7z 1/1 Running 0 6m41s
engine-image-ei-26bab25d-j5972 1/1 Running 0 6m40s
engine-image-ei-26bab25d-qgtnv 1/1 Running 0 6m40s
instance-manager-3d5f1d60a1df63e5736aabfd9def5d1e 1/1 Running 0 6m12s
instance-manager-88ea077425c744e8b67e7496b0a07087 1/1 Running 0 6m1s
instance-manager-968cb0acf46106ca167c39a2633ce055 1/1 Running 0 5m4s
longhorn-csi-plugin-54kqj 3/3 Running 0 5m3s
longhorn-csi-plugin-czc6f 3/3 Running 0 5m4s
longhorn-csi-plugin-zgpc9 3/3 Running 0 5m3s
longhorn-driver-deployer-57b6ff7bf7-88dfx 1/1 Running 0 14m
longhorn-manager-f6zxp 2/2 Running 0 8m23s
longhorn-manager-pkt7h 2/2 Running 0 7m13s
longhorn-manager-r827v 2/2 Running 0 8m23s
longhorn-ui-6797874dbf-g6wqx 1/1 Running 0 14m
longhorn-ui-6797874dbf-xlsjf 1/1 Running 0 14m
Longhorn UIの確認
ポートフォワードしてLonghorn UIを開きます。
kubectl port-forward --namespace longhorn-system service/longhorn-frontend 8080:80
UIのトップページ
各ノードのディスクパスを先ほど作成した/var/lib/longhorn-data に修正します。
動作確認
PVCとPodの作成
1GiのPVCを作成し、それをマウントしたPodでデータを書き込む例を示します。
なお、Longhornをデプロイすると、自動的に longhorn という StorageClass が作成されます。
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: longhorn
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: driver.longhorn.io
allowVolumeExpansion: true
reclaimPolicy: Delete
volumeBindingMode: Immediate
parameters:
numberOfReplicas: "3"
dataEngine: "v1"
fsType: "ext4"
dataLocality: "disabled"
disableRevisionCounter: "true"
そのため、PVCの storageClassName に longhorn を指定することで、Longhorn経由のボリュームが自動的にプロビジョニングされます。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: longhorn-test-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: longhorn
resources:
requests:
storage: 1Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-pod
spec:
replicas: 1
selector:
matchLabels:
app: test-pod
template:
metadata:
labels:
app: test-pod
spec:
initContainers:
- name: init-once-write
image: busybox:latest
command: ["/bin/sh","-c"]
args:
- |
if [ ! -f /data/test.txt ]; then
echo "$(date) - This is a one-time write test" > /data/test.txt;
fi
volumeMounts:
- name: storage
mountPath: /data
containers:
- name: busybox
image: busybox:latest
command: ["/bin/sh","-c"]
args: ["sleep infinity"]
volumeMounts:
- name: storage
mountPath: /data
volumes:
- name: storage
persistentVolumeClaim:
claimName: longhorn-test-pvc
Podは、k8s-worker-3にスケジューリングされています。
$ k get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-pod-dfc4fdc7c-s6dmg 1/1 Running 0 2m23s 10.244.3.45 k8s-worker-3 <none> <none>
ボリュームにデータが書き込まれたことも確認できます。
$ k exec test-pod-dfc4fdc7c-s6dmg -- cat /data/test.txt
Defaulted container "busybox" out of: busybox, init-once-write (init)
Mon Oct 27 06:12:26 UTC 2025 - This is a one-time write test
データの複製確認
/var/lib/longhorn-data/ にレプリカが作成されています。
$ sudo ls -l /var/lib/longhorn/replicas/
total 0
$ sudo ls -l /var/lib/longhorn-data/replicas/
total 4
drwx------ 2 root root 4096 Oct 27 06:12 pvc-40b9b143-d67d-44a1-a066-c1d81b1a0fd4-1a64cc5d
k8s-worker-3だけでなく、k8s-worker-2, k8s-worker-1にも、同様のデータが格納されています。これにより、分散ストレージとしてレプリケーションが機能していることが確認できます。
$ sudo ls -l /var/lib/longhorn-data/replicas/
total 4
drwx------ 2 root root 4096 Oct 27 06:12 pvc-40b943-d67d-44a1-a066-c1d81b1a0fd4-4844e8f5
$ sudo ls -l /var/lib/longhorn-data/replicas
total 4
drwx------ 2 root root 4096 Oct 27 06:12 pvc-40b943-d67d-44a1-a066-c1d81b1a0fd4-a72a9ce0
各ノードの /var/lib/longhorn-data/replicas にレプリカが生成されていることは、UIからも確認できます。
ノード障害時のデータ維持
ここで、k8s-worker-3のVMをシャットダウンする形でノードを意図的に停止します。この時、Podが他ノードで再スケジューリングされてもデータが失われずに保持されます。
Longhorn CSIがPVCを自動的にデタッチ/再アタッチすることで、同じボリュームが新しいノードから継続してアクセス可能になるためです。
k8s-worker-3が利用できなくなり、Podはk8s-worker-1にスケジューリングされるようになりました。
$ k get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-pod-dfc4fdc7c-5pnjg 1/1 Running 0 10m 10.244.1.80 k8s-worker-1 <none> <none>
Nodeを落とし再スケジューリングが行われても、データが失われていないことを確認します。
$ kubectl exec test-pod-dfc4fdc7c-5pnjg -- cat /data/test.txt
Defaulted container "busybox" out of: busybox, init-once-write (init)
Mon Oct 27 06:12:26 UTC 2025 - This is a one-time write test
ノード復旧後の自動リビルド
VMを再起動し、k8s-worker-3が再度k8sクラスタに参加すると、Longhornはそれを検知し、レプリカの再同期(リビルド)を行っていることが、UIから確認できます。
これにより、再び設定通りのレプリカ数が確保され、ボリュームの冗長性が回復します。
まとめ
今回は、KubernetesクラスタにLonghornを用いて分散ストレージの仕組みを導入し、基本的な挙動について確認を行いました。
導入自体は非常にシンプルで、GUIもとても整っており良い体験でした。





