Ubuntu 24.04 上で 12台 HDD の RAID10 ZFS サーバーを構築・運用した際の知見をまとめた実践リファレンス。
公式 man だと散らばっている情報を「やりたいこと」ベースで整理している。
zpool(プール)
└─ vdev(仮想デバイス:mirror / raidz / stripe など)
└─ disk(物理ディスク)
zfs(データセット)
├─ filesystem(ファイルシステム)
├─ volume(ブロックデバイス)
└─ snapshot(スナップショット)
zpool = ストレージの器を管理するコマンド
zfs = その中のデータセット・スナップショットを管理するコマンド
# 全プールの状態一覧
zpool list
# 詳細ステータス(DEGRADED / FAULTED の確認に必須)
zpool status
# 特定プールのみ
zpool status tank
# I/O 統計(読み書き・エラー数)
zpool iostat -v tank 2
# ↑ 2秒ごとに更新
ステータスの見方:
| 状態 | 意味 |
|---|---|
ONLINE |
正常 |
DEGRADED |
冗長性が低下(ディスク障害あり、でも動いてる) |
FAULTED |
プールが使用不可 |
OFFLINE |
管理者が意図的に外した |
REMOVED |
ディスクが物理的に抜かれた |
UNAVAIL |
アクセス不可 |
# mirror(RAID1相当)× 6ペア → RAID10相当
zpool create tank \
mirror sda sdb \
mirror sdc sdd \
mirror sde sdf \
mirror sdg sdh \
mirror sdi sdj \
mirror sdk sdl
# RAIDZ1(RAID5相当)
zpool create tank raidz1 sda sdb sdc sdd
# RAIDZ2(RAID6相当、ディスク2台同時障害まで耐性)
zpool create tank raidz2 sda sdb sdc sdd sde sdf
# SSD を ZIL(書き込みキャッシュ)として追加
zpool add tank log sdm
# SSD を L2ARC(読み込みキャッシュ)として追加
zpool add tank cache sdn
RAID10 vs RAIDZ2: 12台構成なら RAIDZ2×2 より mirror×6 のほうが
ランダム I/O 性能が高く、再構築時間も短い。用途次第で選択。
# 自動マウントを有効化
zpool set autoexpand=on tank
# 圧縮を有効化(pool 全体のデフォルト)
zfs set compression=lz4 tank
# atime を無効化(アクセス時刻更新を止めてI/O削減)
zfs set atime=off tank
# データセット一覧
zfs list
# 特定プール以下を再帰表示
zfs list -r tank
# 全プロパティ確認
zfs get all tank/data
# 特定プロパティだけ確認
zfs get compression,atime,used,available tank/data
# ファイルシステム作成
zfs create tank/data
zfs create tank/backup
zfs create tank/vm
# マウントポイントを指定して作成
zfs create -o mountpoint=/mnt/data tank/data
# 容量クォータを設定して作成
zfs create -o quota=2T tank/user01
# 使用量をわかりやすく表示
zfs list -o name,used,avail,refer,mountpoint
# スナップショット含む詳細
zfs list -t all -r tank
# データセットのサイズ内訳
zfs get used,usedbysnapshots,usedbydataset,usedbychildren tank/data
ZFS 最大の武器。コピーオンライトなので作成は一瞬、容量消費も差分のみ。
# 単一データセットのスナップショット
zfs snapshot tank/data@2026-06-09
# 命名規則:データセット名@スナップショット名
# 日付を入れておくと管理しやすい
# プール以下すべてを再帰的にスナップショット(-r)
zfs snapshot -r tank@2026-06-09_daily
# スナップショットのみ表示
zfs list -t snapshot
# 特定データセットのスナップショット
zfs list -t snapshot -r tank/data
# 使用容量つきで確認
zfs list -t snapshot -o name,used,refer,creation
# スナップショットは .zfs/snapshot/ からそのまま参照可能
ls /mnt/data/.zfs/snapshot/
ls /mnt/data/.zfs/snapshot/2026-06-09/
# 特定ファイルだけ取り出す
cp /mnt/data/.zfs/snapshot/2026-06-09/important.conf /tmp/
# .zfs ディレクトリが見えない場合
zfs set snapdir=visible tank/data
# ロールバック(直前のスナップショットのみ)
zfs rollback tank/data@2026-06-09
# 途中のスナップショットを飛ばして戻す(-r で間のスナップショットを削除)
zfs rollback -r tank/data@2026-06-08
⚠
rollbackはロールバック先より新しいスナップショットを削除する。
迷ったら先にzfs list -t snapshotで確認すること。
# 単体削除
zfs destroy tank/data@2026-06-08
# 再帰削除(子データセットの同名スナップショットも消える)
zfs destroy -r tank@2026-06-08_daily
# 範囲指定削除(2026-06-01 〜 2026-06-07 をまとめて)
zfs destroy tank/data@2026-06-01%2026-06-07
# 初回フル送信
zfs send tank/data@2026-06-09 | ssh backup-server zfs recv backup/data
# 2回目以降は差分のみ送信(-i で増分)
zfs send -i tank/data@2026-06-08 tank/data@2026-06-09 \
| ssh backup-server zfs recv backup/data
# 圧縮して転送(帯域節約)
zfs send tank/data@2026-06-09 | gzip | ssh backup-server "gunzip | zfs recv backup/data"
# pv で転送進捗を確認しながら送信(要 pv)
zfs send -v tank/data@2026-06-09 | pv | ssh backup-server zfs recv backup/data
# scrub 開始(バックグラウンドで全ブロックを検証)
zpool scrub tank
# scrub の進捗確認
zpool status tank
# scrub を中断
zpool scrub -s tank
scrub は月1回以上推奨。 ビットロット(サイレントデータ破損)を早期発見できる。
cron に登録しておくと楽。
# cron 登録例(毎月1日の深夜2時に scrub)
echo "0 2 1 * * root /sbin/zpool scrub tank" >> /etc/cron.d/zfs-scrub
# 状態確認
zpool status tank
# 例: sdc FAULTED 0 0 5 too many errors
# 1. 新しいディスクに交換後、デバイス名を確認
lsblk
# 2. FAULTED ディスクを新ディスクに交換(resilvering 開始)
zpool replace tank sdc sdc # 同じスロットに新ディスク
zpool replace tank sdc sdm # 別デバイス名の場合
# 3. resilvering の進捗確認
zpool status tank
# scan: resilver in progress since ...
# X.XX% done, Y days HH:MM:SS to go
# 4. 完了確認
zpool status tank
# scan: resilvered XXG in HH:MM:SS with 0 errors on ...
# オフライン(ホットスワップ前に実行)
zpool offline tank sdc
# ディスク交換後にオンライン復帰
zpool online tank sdc
# エラー統計をクリア
zpool clear tank
# 特定デバイスのみクリア
zpool clear tank sdc
zpool status tank
# checksum errors が多い場合 → ケーブル/コントローラー疑い
# まず scrub で実際のデータ破損か確認
zpool scrub tank
# scrub 後に repaired が 0 なら「読めてはいる」= ハードウェア起因の可能性
# repaired > 0 なら ZFS が自動修復済み(冗長性があれば)
# ARC サイズと HIT率
arc_summary # arcstat より詳しい(要 zfs-utils)
arcstat 1 # 1秒ごとにリアルタイム表示
# /proc から直接確認
cat /proc/spl/kstat/zfs/arcstats | grep -E "^(hits|misses|size|c_max)"
# 現在の最大サイズ確認(バイト単位)
cat /sys/module/zfs/parameters/zfs_arc_max
# 8GB に制限(再起動まで有効)
echo $((8 * 1024 * 1024 * 1024)) > /sys/module/zfs/parameters/zfs_arc_max
# 永続化(/etc/modprobe.d/zfs.conf に追記)
echo "options zfs zfs_arc_max=8589934592" >> /etc/modprobe.d/zfs.conf
# 圧縮率の確認
zfs get compressratio tank/data
# 重複排除率の確認(dedup 有効時のみ)
zpool get dedupratio tank
# 全データセットの圧縮効果一覧
zfs list -o name,used,refer,compressratio,compression
| やりたいこと | コマンド |
|---|---|
| プール全体の状態確認 | zpool status |
| 容量確認 | zfs list |
| 今すぐスナップショット | zfs snapshot tank/data@$(date +%F) |
| ファイルを過去に戻す | cp /mnt/data/.zfs/snapshot/<名前>/file /tmp/ |
| ディスク故障確認 | zpool status → DEGRADED/FAULTED を探す |
| 定期チェック | zpool scrub tank |
| 別サーバーにバックアップ | zfs send \| ssh ... zfs recv |
| ARC ヒット率確認 | arcstat 1 |
# /usr/local/bin/zfs-snapshot-daily.sh
#!/bin/bash
POOL="tank"
DATE=$(date +%Y-%m-%d)
KEEP=7 # 7世代保持
# スナップショット作成
zfs snapshot -r ${POOL}@${DATE}_daily
# 古いスナップショットを削除(7日より前)
zfs list -t snapshot -o name -H | grep "_daily" | head -n -${KEEP} | xargs -r zfs destroy
# 実行権限を付けて cron に登録
chmod +x /usr/local/bin/zfs-snapshot-daily.sh
echo "0 3 * * * root /usr/local/bin/zfs-snapshot-daily.sh" >> /etc/cron.d/zfs-snapshot
ZFS は「壊れてから気づく」より「壊れる前に検知・バックアップ」が基本思想。
【免責事項:コマンド実行時の注意】
本記事で紹介するコマンドは、システムの設定変更やデータの削除など、影響範囲が広いものを含みます。実行前に必ず内容を確認し、重要なデータはバックアップをとった上で、ご自身の責任において操作を行ってください。誤った操作によるシステムトラブルやデータ消失等について、当方は一切の責任を負いかねます。