Ubuntu で ZFS を使おう! 実践編

さて、実践編です。 以前の記事では、インストーラで ZFS を選択してインストールする紹介をしました。

今回は、稼働している ext4 の Ubuntu にデータ用の ZFS を追加しようというものです。

この構成では、システムが ext4 に置かれ、データ用のストレージが ZFS というハイブリッドな構造になるのですが、これには大きなメリットがあります。

Linux で ZFS を使う場合、前回の記事でも触れたとおり、カーネルのサポートは問題ないのですが、ひとつだけ問題となる可能性があるものが存在します。それは、GRUB の ZFS サポートが弱いということです。これは、カーネルを ZFS 上に置くとブート時に問題が起きる可能性があるということになります。

Ubuntu では、ZFS root でインストールすることを可能にしていますが、GRUB の問題(の可能性)を回避するために、initramfs という仕組みを使っています。

これは initramfs という、RAM disk 上に作られた mini Linux のシステムを立ち上げたあとに、ZFS 上にある完全版カーネルを読みに行くというものです。多少複雑ではありますが、昔から Linux で使われているブートの方式で、実績があり信頼性の高いものではあります。

ext4 root + zfs data の構成であれば、ブートも標準的でシンプルなものになりますし、さらに安心して使える構成だと思います。

それでは、実際に ZFS を Ubuntu に追加したようすを紹介します。

ウチの Ubuntu マシンは、NVMe 2枚刺しで、2枚目をデータディスクにしています。NVMe の価格が高騰している昨今では、随分と贅沢な構成かもしれません。

この2枚目の NVMe を ext4 から ZFS へ移行しました。

インストール

Ubuntu で ZFS を使うためには、まず zfsutils-linux をインストールする必要があります。

$ sudo apt install zfsutils-linux

これだけで、zfs や zpool などの管理コマンドが使えるようになります。カーネルモジュールも自動でロードされるはずですが、再起動するのが確実です。

デバイス名の確認

まず、使用するストレージのデバイス名(デバイスファイル名)を確認しておきます。

$ sudo fdisk -l

私の場合は NVMe でしたので、/dev/nvme1n1 というデバイスファイルでした。SATA HDD/SSD の場合は、/dev/sda や /dev/sdb になると思います。

pool の作成

使用するストレージに pool を作成します。pool とは、複数のストレージをまとめて一つの仮想化されたストレージにする仕組みです。単独のストレージであっても、pool を作成します。

一般的な論理ボリュームは、ext4 などのファイルシステムをいろいろなツールでまとめて仮想化することで実現されていますが、ZFS ではこれがすべてzpool コマンドで一体化されています。
いろいろな RAID の構成も、zpool ひとつで実現できます。

ストレージが一つだけの場合は次のようにします。

# zpool create <pool名> <device>

pool 名は何でもかまいません。私はだいたい zdata という名前にしています。具体例です。

$ zpool create zdata /dev/nvme1n1

2台のストレージでミラーリング構成(いわゆる RAID1)にする場合は、

$ zpool create zdata mirror /dev/sdb /dev/sdc

のようにします。

これだけで、zdata という pool が作られ、 /zdata という、pool 名と同じ名前のディレクトリに自動的にマウントされて、すぐに使える状態になっています。

一般的に Linux で RAID を組む場合、① mdadm --create ② mkfs.ext4 ③ /etc/mdadm.conf の編集 ④ /etc/fstab の編集、というステップが必要ですが、ZFS では zpool create 一発でできてしまいます。しかも、一瞬で終わります。(mdadm + mkfs だと、5〜10分はかかります)

dataset の作成

pool 単体でも使えるのですが、一般的に、dataset という単位に分割して使います。snapshot や quota、圧縮なども dataset 単位で行うようになっているのと、区分したほうが使いやすいからです。ディスクをパーティションに分けるのと似ていますが、容量が可変であらかじめ決めておく必要がないので非常に柔軟性に優れています。

dataset を作るのも簡単です。

# zfs create <pool名>/<dataset名>

実行例としては、

$ sudo zfs create zdata/data

みたいな感じです。この場合、自動的に /zdata/data にマウントされるようになっています。

別の場所にマウントしたい場合は、

$ sudo zfs set mountpoint=/data zdata/data

のようにすることも可能です。ちょっとわかりにくいのですが、zdata/data が  /data にマウントされるようになります。mount コマンドや df コマンドで確認すると、納得できると思います。

さらにややこしいのは、dataset が

<pool名>/<親dataset>/<子dataset>

のようにいくらでも階層構造にできることで、どの階層をどこにマウントすることもできることです。例えば、

$ sudo zfs set mountpoint=/child zdata/data/child

のようにもできます。

この dataset 単位で、snapshot、圧縮、暗号化、NFS の export、backup、quota(容量制限)など、ファイルシステムに関することは何でもできるので、それらの必要に応じて dataset の分割を行うことになります。

あまりにも柔軟で迷宮に入りそうですが、どのように snapshot を撮るかで考えるのが一般的でしょう。

よく行われているのは、仮想マシンのフォルダごとに dataset を分けて snapshot を撮るということでしょうか?

ホームディレクトリの移行

もう一つ、ホームディレクトリを dataset にしておくと便利です。システムとデータに分かれている今回の方法の場合は、ホームディレクトリは ext4 のシステム側にあるはずです。これを ZFS の dataset に移しましょう。

まず、dataset を作ります。/home に二重にマウントされないように名前を home.new に変えておきましょう。この例では、/home/user を ext4 から ZFS へ移行させます。

$ sudo zfs create zdata/home.new
$ sudo zfs create zdata/home.new/user

これで、作ったデータセットは /zdata/home.new/user にマウントされているはずなので、所有者を root から user に変えておきます。

$ sudo chown user zdata/home.new/user

ホームディレクトリのまるごとコピーには、rsync というコマンドを使います。

$ sudo apt install rsync
$ sudo rsync -av /home/user/ /zdata/home.new/user/

注意:ディレクトリの最後を '/' で終わらせるのをお忘れなく。

次に元のホームディレクトリの名前を変えます。

$ sudo mv /home /home.old

ZFS 側の名前を変えます。

$ sudo zfs rename zdata/home.new zdata/home

※ 子 dataset の zdata/home.new/user も自動的に zdata/home/user に変わります。

マウントポイントを /home にしておきます。

$ sudo zfs set mountpoint=/home zdata/home
$ sudo zfs set mountpoint=/home/user zdata/home/user

zdata/home/user のマウントポイントは自動的には /home/user になってくれませんので、忘れずに set mountpoint しておきましょう。

これで、ホームディレクトリの移行は完了です。しばらく使って大丈夫だと思ったら、/home.old 以下は消してしまっても OK です。

VirtualBox や KVM などの仮想マシンがある場合には、/home と同じようなやり方で、仮想マシンごとに dataset を作ってやると非常に管理しやすくなります。
ZVOL という専用の仕組みもありますので、機会があれば紹介したいと思います。

snapshot の撮り方

ZFSでは非常に簡単に snapshot が撮れます。

# zfs snapshot <dataset名>@<snapshot名>

具体例です。

$ sudo zfs snapshot zdata/home/user@snap-202605231800

確認は、zfs list で行います。

$ zfs list -t snapshot
NAME                                                      USED AVAIL REFER MOUNTPOINT
zdata/home/user@snap-202605231800  0B         -        96K           - 

-t snapshot をつけることで、snapshot だけのリストを出力できます。

次のようにしておけば、ユーザー権限でも snapshot が撮れるようになります。(sudo なしで実行可能になる)

$ sudo zfs allow user snapshot

実は、rollback や destroy も allow することができるのですが、誤って消してしまったりする事故を防止するため、allow するのは snapshot だけにした方が良いです。

btrfs の snapshot と比較すると、ZFS の snapshot がいかに簡単かがわかります。

btrfs では、

btrfs subvolume snapshot /home /home/.snapshots/2026-05-23

のように、snapshot を path 名で指定する必要があります。つまり保存場所名前を指定する必要があるのです。例は標準的なやり方なのですが、この場合、.snapshots というディレクトリをあらかじめ作っておく必要があります。名前だけ指定すれば良い ZFS の snapshot と比較すると、どこに snapshot を置くかまで管理する必要があり、かなり手間を感じます。

ZFS では、snapshot を撮ると、dataset の直下に .zfs/ という、ディレクトリのようなものが作られます。この中には、snapshot を撮った時点のファイルやディレクトリが入っているように見え、これを

cp .zfs/xxx <どこか>

のようにすると、ファイルの実体として復活するようになっていて、誤ってファイルを消したときなどに rollback せずにファイルを簡単に復活させることができます。非常に便利です。

.zfs はディレクトリではなく、読み込み専用の不思議なもので、ls -a しても見えませんが、ls .zfs すると中身を見ることができます。

参考リンク

OpenZFS

Ubuntu Tutorial

Arch Linux ZFS

まとめ

このようにして我が家のスーパーコンピュータ、zen4 Ryzen9 の Ubuntu マシンは ext4 と ZFS のハイブリッド構成になりました。しばらくこれで使ってみて、もし問題が発生するようなら note で記事にしたいと思います。(もしかしたら、「Linux で ZFS はやめておいたほうが良い」ということになるかもしれません。)

ちなみに Linux MINT で確認すると、apt install zfsutils-linux でインストールできましたので、debian/ubuntu 系では大抵同じように ZFS できると思います。ぜひ挑戦してみてください。


いいなと思ったら応援しよう!