Ubuntu Weekly Recipe

第597回 UbuntuのルートファイルシステムをZFSにしてみる

この記事を読むのに必要な時間:およそ 13 分

インストール直後の状態確認

まずはインストール直後の状態を確認してみましょう。最初にパーティションレイアウトを見てみます。

$ sudo parted /dev/vda unit MiB print
モデル: Virtio Block Device (virtblk)
ディスク /dev/vda: 20480MiB
セクタサイズ (論理/物理): 512B/512B
パーティションテーブル: gpt
ディスクフラグ:

番号  開始     終了      サイズ    ファイルシステム  名前                  フラグ
 1    1.00MiB  513MiB    512MiB    fat32             EFI System Partition  boot, esp
 2    513MiB   563MiB    50.0MiB   ext4
 3    563MiB   1486MiB   923MiB    linux-swap(v1)
 4    1486MiB  3534MiB   2048MiB   zfs
 5    3534MiB  20480MiB  16946MiB  zfs

最初のパーティションはEFI System Partition(ESP)です。今回はUEFIファームウェアを利用したため,EFI OSローダー(GRUBやセキュアブート用のshimなど)を保存するためのESPが作られています。ESPはFAT12/16/32のいずれかである必要があるため,ZFSで作ることはできません。

第2パーティションはGRUBの設定ファイルやモジュール類をインストールする領域です。GRUB自体はinsmod zfsを実行して初めてZFSの内容を確認できます。つまりGRUBがカーネルやinitramfsをZFSからロードするためには,GRUBのモジュール類はGRUBが標準でサポートしているファイルシステムに置かれている必要があるのです。このための領域をext4として作成しています。

ただしこれはESPと分離する意味があまりないため,Ubuntu 20.04 LTSからはESPに統合されます。結果としてBIOSモードでも(UEFIが動かない環境でも⁠⁠,ESP相当のGRUBモジュールがインストールされるパーティションが作られます。

第3パーティションは見てのとおりスワップパーティションです。Ubuntuは17.04からスワップパーティションを作らずに,ファイルシステム上のスワップファイルを利用することになりました。ZFSはスワップファイルを使えないため,明示的にスワップパーティションを作っています。ちなみにZFS上にスワップ用のボリュームを作ることも可能です※7⁠。この部分は将来的に変わるかもしれません。

※7
可能ではあるのですが,デッドロックする問題が存在するようです

第4パーティションと第5パーティションがZFS用のパーティションです。前者が起動カーネルなどを保存する「/boot」用,後者がそれ以外のデータを保存するルートファイルシステム用に用意されています。

ちなみにリリースノートで指摘されていたインストーラーがストレージをフォーマットする際にZFSがなくext4だけ表示される問題は,パーティションフォーマットの確認ダイアログで,第3パーティション以降が表示されないことを意味しています。

図2 vda上にZFSを作ったのにESPとext4しか表示されない

画像

ZFSパーティションのレイアウトを計算するのは,このパーティション確認ダイアログが表示されるタイミングよりも後ろだったのです。つまり第1と第2しか表示されないので,⁠ZFSを選択したのにext4を作ろうとしている」と勘違いするような表記になっていました。これがリリースノートで「動作としては正しいのですが,利用者に混乱を引き起こす表示」と記載された理由となります。

Ubuntu 20.04 LTSのインストーラーでは,ダイアログが表示されるタイミングでZFSのパーティション情報も表示するように修正されています。

次に/etc/fstabがどうなっているか確認してみましょう。

$ cat /etc/fstab
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
# /boot/efi was on /dev/vda1 during installation
UUID=8977-6786  /boot/efi       vfat    umask=0077      0       1
UUID=0a9b50b8-7a66-4ae1-8a7d-35796345aca0       /boot/grub      ext4    errors=remount-ro       0       1
UUID=892fa4dc-22ef-49fa-9340-2676ce19cbd7       none    swap    discard 0       0

あれ,ルートファイルシステムのエントリーが存在しませんね。実はZFSにはそのファイルシステム情報の中に「マウントポイント」を記録するフィールドが存在します。

ストレージプールのレイアウト

それでは今度は実際にZFSの情報を表示してみましょう。最初にZFSには「ストレージプール」「データセット」というふたつの概念が存在します。

ストレージプールはいわゆるボリューム管理のような機能です。複数のストレージデバイス・パーティションをまとめて,ひとつのボリュームのように扱います。Ubuntu 19.10のインストーラーでは単一のパーティションから単一のプールを作成していますが,複数のストレージデバイスをひとつのプールとしてストライピングやミラーリングしたり,RAIDのように信頼性・可用性を向上させることも可能になっています。また,ZFSとしてのログデバイスやキャッシュを別のより少量・高速なデバイスに指定するなど,かなり柔軟な構成が可能です。

ストレージプールの操作はzpoolコマンドで行います。

$ zpool list
NAME    SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP    HEALTH  ALTROOT
bpool  1.88G   159M  1.72G        -         -      -     8%  1.00x    ONLINE  -
rpool  16.5G  3.98G  12.5G        -         -     5%    24%  1.00x    ONLINE  -

先ほども説明したように,Ubuntuではふたつのストレージプールを用意しています。詳細はzpool statusコマンドで確認できます。

$ zpool status
  pool: bpool
 state: ONLINE
status: The pool is formatted using a legacy on-disk format.  The pool can
        still be used, but some features are unavailable.
action: Upgrade the pool using 'zpool upgrade'.  Once this is done, the
        pool will no longer be accessible on software that does not support
        feature flags.
  scan: none requested
config:

        NAME        STATE     READ WRITE CKSUM
        bpool       ONLINE       0     0     0
          vda4      ONLINE       0     0     0

errors: No known data errors

  pool: rpool
 state: ONLINE
  scan: none requested
config:

        NAME        STATE     READ WRITE CKSUM
        rpool       ONLINE       0     0     0
          vda5      ONLINE       0     0     0

errors: No known data errors

Software Design 2019年12月号でも詳しく説明しているように,bpoolは少し特殊です。bpool(/boot)はカーネルやinitramfsが保存される領域なので,GRUBから見えなくてはなりません。しかしながらGRUBのZFSモジュールは,ZFSのすべての機能を実装しているとは限りません。

そこでbpoolについてはより保守的な使い方であることを明示するために,featureフラグをすべて落としてバージョン名を明記しているのです。これが上記で言うところの「a legacy on-disk format」です。zpool get allコマンドでversionプロパティを見ても,bpoolだけバージョンが設定されていることがわかります。

$ zpool get all | grep version
bpool  version                        28                             local
rpool  version                        -                              default

よってbpoolについては,アップグレードは実行しないでください。スナップショットやバックアップといった基本的な機能は使えるので,そのままでも実用上問題はないはずです。

ちなみにUbuntu 20.04 LTSでは,必要なfeatureフラグがセットされたbpoolが作られます。つまりUbuntu 20.04 LTSのインストーラーを用いてインストールした環境だと,上記の警告はでなくなるはずです。

データセットのレイアウト

ストレージプールは論理ボリュームのようなものです。ここから実際に読み書きできる領域として切り出したものが「データセット」です。データセットには「ファイルシステム」⁠ボリューム」⁠スナップショット」⁠ブックマーク」の4種類が存在します。

ファイルシステムはその名の通りファイルシステムです。実際にファイルシステムのどこかにマウントされ,読み書きる状態になります。もっとも基本的な種類です。ZFSではストレージプールをブロックデバイスとして切り出せます。これが「ボリューム」です。たとえばKVMなどの仮想マシン用のストレージデバイスを作りたい際に利用します。

ファイルシステムやボリュームは,ある時点の状態を「スナップショット」として保存し,必要に応じてリストアできます。それに対して「ブックマーク」「ある時点」のみを記録するラベルのような仕組みです。差分バックアップを生成する際に有用になります。

Ubuntuインストール直後に使われているデータセットはファイルシステムだけです。データセットのリストはzfs listコマンドで確認できます。

$ zfs list
NAME                                               USED  AVAIL     REFER  MOUNTPOINT
bpool                                              159M  1.59G      176K  /boot
bpool/BOOT                                         158M  1.59G      176K  none
bpool/BOOT/ubuntu_08z65m                           158M  1.59G      158M  /boot
rpool                                             3.98G  12.0G       96K  /
rpool/ROOT                                        3.98G  12.0G       96K  none
rpool/ROOT/ubuntu_08z65m                          3.98G  12.0G     3.49G  /
rpool/ROOT/ubuntu_08z65m/srv                        96K  12.0G       96K  /srv
rpool/ROOT/ubuntu_08z65m/usr                       200K  12.0G       96K  /usr
rpool/ROOT/ubuntu_08z65m/usr/local                 104K  12.0G      104K  /usr/local
rpool/ROOT/ubuntu_08z65m/var                       495M  12.0G       96K  /var
rpool/ROOT/ubuntu_08z65m/var/games                  96K  12.0G       96K  /var/games
rpool/ROOT/ubuntu_08z65m/var/lib                   492M  12.0G      379M  /var/lib
rpool/ROOT/ubuntu_08z65m/var/lib/AccountServices    96K  12.0G       96K  /var/lib/AccountServices
rpool/ROOT/ubuntu_08z65m/var/lib/NetworkManager    128K  12.0G      128K  /var/lib/NetworkManager
rpool/ROOT/ubuntu_08z65m/var/lib/apt              77.5M  12.0G     77.5M  /var/lib/apt
rpool/ROOT/ubuntu_08z65m/var/lib/dpkg             35.6M  12.0G     35.6M  /var/lib/dpkg
rpool/ROOT/ubuntu_08z65m/var/log                  1.96M  12.0G     1.96M  /var/log
rpool/ROOT/ubuntu_08z65m/var/mail                   96K  12.0G       96K  /var/mail
rpool/ROOT/ubuntu_08z65m/var/snap                  112K  12.0G      112K  /var/snap
rpool/ROOT/ubuntu_08z65m/var/spool                 112K  12.0G      112K  /var/spool
rpool/ROOT/ubuntu_08z65m/var/www                    96K  12.0G       96K  /var/www
rpool/USERDATA                                    3.44M  12.0G       96K  /
rpool/USERDATA/root_e8xd45                         112K  12.0G      112K  /root
rpool/USERDATA/shibata_e8xd45                     3.24M  12.0G     3.24M  /home/shibata

多いですね。Ubuntuでは大雑把な重要度と用途に合わせてデータセットを分けているようです。データセットの名前は「ストレージプール/名前」で指定されます。名前のubuntu_root_shibata_の後ろの英数字はインストール時に自動生成したランダムな6文字となります。

注目すべきは「MOUNTPOINT」です。これはデータセットのmountpointプロパティの値であり,ZFSをマウントしたときに自動的にマウントポイントとして利用されるパスになります。

つまりZFSは/etc/fstabにルートファイルシステムを明示的に書かなくても,ZFS配下のデータセットが適切な場所にマウントされるというわけです。

ちなみにGRUBは,カーネルについてはbpool以下のデータセットのパスを,ルートファイルシステムについてはrpoolも含めたパスを指定します。

$ cat /proc/cmdline
BOOT_IMAGE=/BOOT/ubuntu_08z65m@/vmlinuz-5.3.0-23-generic root=ZFS=rpool/ROOT/ubuntu_08z65m ro quiet splash vt.handoff=1

上記のroot=がルートファイルシステムの指定です。

GRUBのデータセットの指定方法は,update-grub実行時にzfsコマンドを駆使して行います。詳細は/etc/grub.d/10_linux_zfsのスクリプトを確認してください。

著者プロフィール

柴田充也(しばたみつや)

Ubuntu Japanese Team Member株式会社 創夢所属。数年前にLaunchpad上でStellariumの翻訳をしたことがきっかけで,Ubuntuの翻訳にも関わるようになりました。