ストレージはProxmoxの静かな弱点——多くの人が見落としがちな問題
自分のホームラボでProxmox VEを使って12台のVMとコンテナを管理している——本番環境に持っていく前にあらゆるものをテストするための遊び場だ。最初はProxmoxインストーラーが自動で作成するデフォルトのLVM-Thinを使っていた。それで問題なかった。あるNVMeドライブにバッドセクタが出るまでは。気づかないうちにデータがサイレントコラプションしており、VMは起動するもののその中のデータベースが原因不明のエラーを報告し始めた。それがZFSを真剣に検討するきっかけだった。
Proxmox VEのストレージアプローチを比較する
Proxmoxはさまざまなストレージバックエンドをサポートしている。選択する前に、それぞれのトレードオフをしっかり理解しておく必要がある。
LVM / LVM-Thin(デフォルト)
Proxmoxインストーラーは確認なしで自動的にLVM-Thinを作成する——起動すればすぐ使える。LVM-Thinにはシンプロビジョニングとスナップショットがあるが、チェックサムもセルフヒーリングもない。セクタが壊れても、VMがクラッシュするかデータがいつの間にか破損するまで気づかない。
- メリット:シンプル、オーバーヘッドが低い、すぐに使える標準サポート
- デメリット:データ整合性チェックがない、ボリュームが大きいとスナップショットが遅い
Directory(ext4/xfs)
VMディスクを通常のファイルシステム上にrawまたはqcow2ファイルとして保存する。rsyncでバックアップが簡単で、追加のセットアップも不要だ。ただしqcow2経由のスナップショットは遅く、時間の経過とともにフラグメンテーションが起きやすく、I/Oパフォーマンスに影響する。
ZFS(zvol + dataset)
ボリュームマネージャー、チェックサム、スナップショット、圧縮、スクラブをストレージ層に統合したファイルシステム。ZFSにはハードウェアRAIDコントローラーが不要——冗長性とデータ整合性を自ら管理する。
- メリット:全ブロックのチェックサム、アトミックな即時スナップショット、ネイティブ圧縮(lz4)、スクラブによる早期エラー検出
- デメリット:RAM使用量が多い(最低推奨は1TBのストレージに対して1GBのRAM)、作成後にプールを縮小できない
Ceph(マルチノードクラスター向け)
3ノード以上のクラスター向けに設計された分散ストレージ。シングルサーバーでCephをセットアップするのは手間に見合わない——最低3台のマシンがない場合はこの選択肢をスキップすべきだ。
分析:ZFSの強みと弱みはどこにあるか?
ZFSがすべてのストレージ問題を解決するわけではない。しかし重要なデータでProxmoxを運用する場合、他のどの選択肢よりも優れている点が2つある。
- サイレントコラプション検出:各ブロックにチェックサムが付与される(SHA-256またはblake3)。読み取り時にZFSはチェックサムを検証——一致しない場合、ブロックが壊れていることを検知し、mirror/RAIDZであれば正常なコピーから自動修復する。
- アトミックスナップショット:ZFSのスナップショットは、ボリュームが100GBでも2TBでもミリ秒で作成される。VMを長時間フリーズさせる必要がなく、I/Oへの影響もほとんどない。
LVM-Thinの場合、VMがクラッシュするかデータベースが奇妙なエラーを報告するまで問題に気づかなかった。ZFSのスクラブは毎週実行されログに直接報告する——被害が発生する前に把握できる。後になってから気づくのではなく。
いつProxmoxにZFSを選ぶべきか?
以下の条件を満たしている場合はZFSを選択しよう。
- サーバーのRAMが16GB以上(ZFS ARCキャッシュはRAMを多く使うが、その価値は十分にある)
- バックアップワークフローやテストのために高速スナップショットが必要
- 重要なデータがあり、手遅れになる前にハードウェアエラーを検出したい
- パフォーマンスを犠牲にせずに容量を節約するための圧縮が必要
RAMが8GB未満の場合、ZFSはパフォーマンスを改善するどころか低下させてしまう。プールを縮小する必要がある場合も避けるべきだ——一度プールを作成すると、小さくする方法はない。
Proxmox VEへのZFS導入手順
Proxmox VE 7以降にはZFSカーネルモジュールが同梱されている。ext4ルート(インストール時にZFSを選択しなかった場合)にProxmoxをインストールした場合は、以下のパッケージを追加する必要がある。
ステップ1:ZFSモジュールの確認とインストール
# ZFSが既にインストールされているか確認
zfs version
# インストールされていない場合はインストール
apt update && apt install zfsutils-linux
# カーネルモジュールをロード
modprobe zfs
# モジュールがロードされたことを確認
lsmod | grep zfs
ステップ2:プール作成用ディスクの確認
# ディスクの一覧を確認
lsblk -o NAME,SIZE,TYPE,MOUNTPOINT
# /dev/sdXより安定したディスクIDを確認
ls -l /dev/disk/by-id/ | grep -v part
常に/dev/sdXの代わりにディスクのby-idを使用すること——再起動後にディスクの順番が変わり、プールが壊れる可能性がある。
ステップ3:ZFSプールの作成
1TBのディスクが2台あると仮定して、冗長性と読み取りパフォーマンスの両方を確保するためにミラープール(RAID-1相当)を作成する。
# ディスクIDを使ってミラープールを作成(最も安全な方法)
zpool create -f rpool_vm mirror \
/dev/disk/by-id/ata-WDC_WD10EZEX-xxxxxxxx \
/dev/disk/by-id/ata-WDC_WD10EZEX-yyyyyyyy
# 3台のディスクがある場合はRAIDZ1を使用(RAID-5相当だがwrite holeがない)
# zpool create -f rpool_vm raidz1 /dev/disk/by-id/... /dev/disk/by-id/... /dev/disk/by-id/...
# プールが作成されたことを確認
zpool status rpool_vm
zpool list
ステップ4:VMワークロード向けの最適なプロパティ設定
# lz4圧縮を有効にする(高速で~20-40%の容量削減)
zfs set compression=lz4 rpool_vm
# atimeを無効にする(不要な書き込みオーバーヘッドを削減)
zfs set atime=off rpool_vm
# プロパティが適用されたことを確認
zfs get compression,atime rpool_vm
ステップ5:Proxmox VEへのZFSプールの追加
Proxmox Web UI → Datacenter → Storage → Add → ZFS に進み、以下を入力する。
- ID:Proxmox内のストレージ名(例:
zfs-vm) - ZFS Pool:
rpool_vm - Content:Disk image, Container
- Block Size:8K(ほとんどのVMワークロードに適している)
またはCLIで素早く追加する場合:
pvesm add zfspool zfs-vm --pool rpool_vm --content images,rootdir
VMでのZFSスナップショット活用
ZFS上のProxmoxでは、各VMディスクはzvolとして保存される。ZFSのスナップショットはブロック層で動作するため、非常に高速だ。
手動スナップショットの作成とロールバック
# VMのzvolの一覧を確認
zfs list | grep vm-
# システム更新前にVM 100のスナップショットを作成
zfs snapshot rpool_vm/vm-100-disk-0@before-update-2024-01
# すべてのスナップショットを確認
zfs list -t snapshot
# 問題が発生した場合にロールバック(VMを停止してから実行)
qm stop 100
zfs rollback rpool_vm/vm-100-disk-0@before-update-2024-01
qm start 100
日次自動スナップショット
#!/bin/bash
# /usr/local/bin/zfs-auto-snapshot.sh
# 毎日実行し、直近7件のスナップショットを保持
POOL="rpool_vm"
DATE=$(date +%Y%m%d-%H%M)
KEEP=7
# プール内のすべてのzvolにスナップショットを作成
for zvol in $(zfs list -H -o name -t volume | grep "^${POOL}/vm-"); do
zfs snapshot "${zvol}@auto-${DATE}"
echo "Snapshot: ${zvol}@auto-${DATE}"
done
# 古いスナップショットを削除し、各zvolで直近$KEEP件を保持
for zvol in $(zfs list -H -o name -t volume | grep "^${POOL}/vm-"); do
snapshots=$(zfs list -H -o name -t snapshot | grep "^${zvol}@auto-" | sort)
count=$(echo "$snapshots" | wc -l)
if [ "$count" -gt "$KEEP" ]; then
echo "$snapshots" | head -n $((count - KEEP)) | xargs -I{} zfs destroy {}
fi
done
# crontabに追加:毎日午前2時に実行
crontab -e
# 以下の行を追加:
0 2 * * * /usr/local/bin/zfs-auto-snapshot.sh >> /var/log/zfs-snapshot.log 2>&1
ChecksumとScrub——データ整合性を守る防衛層
ZFSはブロックを読み取るたびに自動的にチェックサムを検証する。しかし読み取り頻度の低いデータ(コールドデータ)については、定期的なスクラブだけがプール全体をスキャンできる。
# プール全体のスクラブを実行
zpool scrub rpool_vm
# 進捗を確認
zpool status rpool_vm
# スクラブ完了時の出力例
# scan: scrub repaired 0B in 00:04:21 with 0 errors on Sun Mar 15 03:00:02 2026
0 errorsはプールが正常であることを意味する。エラーが検出されると、mirrorまたはRAIDZのZFSは正常なコピーから自動修復しログに記録する——クラッシュのデバッグではなく、ログを読むだけでいい。LVM-Thinの場合、同じシナリオはVMが起動不能という結末で終わる。
# 毎週日曜日の午前3時に自動スクラブ
# crontabに追加:
0 3 * * 0 zpool scrub rpool_vm
# 実際の圧縮率を確認
zfs get compressratio rpool_vm
# I/Oをリアルタイムで監視
zpool iostat rpool_vm 2
ZFSへの移行後の実際の結果
ホームラボをLVM-Thinからlz4圧縮付きのZFSミラーに移行したところ、VMによって圧縮率は1.4x〜1.8x程度になった——テキストやログが多いVMが最も恩恵を受ける。スナップショットは数分かかっていたのが即座に作成されるようになった。最も評価しているのは、毎週のスクラブが0 errorsを報告することだ。ストレージが自分でデータ整合性を監視してくれる——LVM-Thinの頃のように運任せにする必要がなくなった。
十分なRAMがあり、重要なデータを扱うなら——これは避けられないアップグレードだ。追加のハードウェアコストは不要で、一度正しくセットアップする時間だけあればいい。

