FreeBSD 11.1-RELEASEを自由なZFSパーティション構成でインストールする

bsdinstallの登場により、FreeBSD 10あたりからRoot on ZFSでのインストールが簡単に出来るようになった。

一方で、昔ながらの手動でRoot on ZFSを作っていたユーザーは、ZFSのファイルシステム構成やプロパティを自由に設定したいと考えるだろう。かくいう自分もその一人である。最近のFreeBSDのインストール作法を踏まえつつ、手動でZFSルートファイルシステムを作る方法が分かったので、備忘録も兼ねて記事にする。

  • ストレージのパーティションの1つをルートプールとして使いたい!
    • bsdinstallだとストレージ全体がzpoolにされてしまう…
    • ストレージ全体を割り当てた場合、デバイスが死んだ際に交換先の容量誤差で交換できない可能性が微レ存…
  • データセットの階層をデフォルトから変えたい!
    • 標準インストールではプール直下に/usrとかが作られる(zroot/usr的な)けど、間に1つ階層を挟みたいんじゃー(zroot/sys/usr的な)
    • プール直下だとsnapshotの扱いが面倒だったりする
  • データセット作成時にしか指定できないプロパティを変更したい!
    • utf8onlyで運用したいじゃん?
    • compressionなんかも最初から有効にした方が効くじゃん?
  • ストレージ構成以外はbsdinstallに任せたい!
    • なんだかんだ言ってdialog(1)でIPアドレスとか設定できた方がが分かりやすいし…
    • その時々の時流に応じてインストーラで設定出来ることが追加されてたりするし…
      • 最近のインストーラではsendmailの無効化やPIDのランダム化が設定出来るようになっててびっくりしたよ
  • FreeBSD 11.0-RELEASE
  • FreeBSD 11.1-RELEASE
  • レガシーブート環境(非UEFIブート)

bsdinstall以降のリリースならどれにでも適用できると思われる。

お作法は至ってシンプルで、インストール環境の/mnt=インストール先のルートディレクトリ(/)となるように、ファイルシステムを作ってマウントしてあげれば良い。あとはbsdinstallが全部やってくれる。

操作は全てインストーラのシェルで行う。

# kldload zfs

実はzpool, zfsコマンドを実行した時に勝手にロードされるんだけど、モジュールを読み込んでおかないと次に設定する4kセクタ用のカーネル変数が生えてこないのである。

ZFSのプールを4kセクタで作るためのおまじない

# sysctl vfs.zfs.min_auto_ashift=12
vfs.zfs.min_auto_ashift: 9 -> 12

ディスク全体の以前のZFS情報を消す

# zpool labelclear -f da0

HDDのパーティションを切る

ここはお好みで。将来のUEFIブート移行を見越してESPを確保してある。またスワップは専用パーティションにしたい派。

# gpart create -s gpt da0
# gpart add -a 4k -t efi -s 512m da0
# gpart add -a 4k -t freebsd-boot -s 512k da0
# gpart add -a 4k -t freebsd-zfs -s 30g da0
# gpart add -a 4k -t freebsd-swap -s 16g da0
# gpart add -a 4k -t freebsd-zfs -s 40g da0

確認

# gpart show da0
=>       40  195312424  da0  GPT  (93G)
         40    1048576    1  efi  (512M)
    1048616       1024    2  freebsd-boot  (512K)
    1049640   62914560    3  freebsd-zfs  (30G)
   63964200   33554432    4  freebsd-swap  (16G)
   97518632   83886080    5  freebsd-zfs  (40G)
  181404712   13907752       - free -  (6.6G)

パーティション毎の以前のZFS情報を消す(念の為)

# zpool labelclear -f da0p1
# zpool labelclear -f da0p2
# zpool labelclear -f da0p3
# zpool labelclear -f da0p4

ルートプールを作る

デフォルトインストーラによるプロパティの設定はcompressionとatimeのみ。他のプロパティや値はご自由に。

# zpool create -o altroot=/mnt -o cachefile=/tmp/zpool.cache -O mountpoint=none -O compression=lz4 -O atime=off -O normalization=formC zroot da0p3

4kセクタで作られたか確認

# zdb -U /tmp/zpool.cache | grep ashift
            ashift: 12

各種ZFSファイルシステムを作る

デフォルトのプロパティ設定は「FreeBSD 11.1-RELEASEのZFS構成とプロパティ一覧」を参照してくだしあ。

デフォルトシステムのFSを作成。

zfs create -o mountpoint=/ -o canmount=noauto -p zroot/sys/ROOT/default
zfs mount zroot/sys/ROOT/default

最近のFreeBSD on ZFSでは、Solaris由来のBoot Environmentという考えを意識しているようで、ルートプールのbootfsで指定したFS──デフォルトではzroot/ROOT以下の複数のシステムをブート時に切り替えられるようになっている。zroot/ROOT/defaultというのは、その名の通りデフォルトのシステムが入ることになる。

これらシステムFSのcanmountはnoautoになるので、自動マウントは行われない。起動時に選択されたシステムはブートローダによって、設定されたmountpoint、つまりルートディレクトリにマウントされることでアクティブなシステムとなる仕組み。

後続のFS作成のため、作成後は必ずzfs mountすること。インストーラ環境の/mntは読み込み専用となっているため、作成したインストール先でオーバーレイしてやらないと、後続のFS作成時にマウントポイントが作れないエラーになる。

その他、必要なFSを作る。

zfs create -o mountpoint=/tmp -o exec=on -o setuid=off zroot/sys/tmp
zfs create -o mountpoint=/usr -o canmount=off zroot/sys/usr
zfs create -o mountpoint=/usr/ports -o compression=gzip-9 -o setuid=off zroot/sys/usr/ports
zfs create -o mountpoint=/usr/src -o compression=gzip-9 zroot/sys/usr/src
zfs create -o mountpoint=/var zroot/sys/var
zfs create -o mountpoint=/var/audit -o exec=off -o setuid=off zroot/sys/var/audit
zfs create -o mountpoint=/var/crash -o exec=off -o setuid=off zroot/sys/var/crash
zfs create -o mountpoint=/var/log -o exec=off -o setuid=off zroot/sys/var/log
zfs create -o mountpoint=/var/mail -o atime=on zroot/sys/var/mail
zfs create -o mountpoint=/var/tmp -o setuid=off zroot/sys/var/tmp

/usrがcanmount=offであることに注意。

これらFSは上述のROOT/defaultのマウント後にオーバーレイ的にマウントされ、/以下はzpool/ROOT/defaultとzroot/usr等が重なり合い入り混じった状態となる。この辺は従来のUFSと大きく違う所なので、よーく理解しておく必要がある。UnionFSの挙動に近いかも?

ホームディレクトリは別プールに起きたいので作成。ルートプールのままでいいなら、ルートプールに作って下しあ。

zpool create -o altroot=/mnt -O mountpoint=legacy -O compression=lz4 -O atime=off -O normalization=formC zdata da0p5
zfs create -o mountpoint=/usr/home -p zdata/ROOT/home

パーミッションの設定

chmod 1777 /mnt/tmp
chmod 1777 /mnt/var/tmp

ZFSが以下のような感じで作られマウントされてればOK。重要なのはzroot/ROOT/defaultに相当するFSが/mntにマウントされていること、zroot/usr等が/mntをルートとしてマウントされていること。

# zfs list
NAME                     USED  AVAIL  REFER  MOUNTPOINT
zdata                    516K  38.5G    96K  /mnt/zdata
zdata/ROOT               192K  38.5G    96K  /mnt/zdata/ROOT
zdata/ROOT/home           96K  38.5G    96K  /mnt/usr/home
zroot                      2M  28.8G    96K  none
zroot/sys               1.23M  28.8G    96K  none
zroot/sys/ROOT           192K  28.8G    96K  none
zroot/sys/ROOT/default    96K  28.8G    96K  /mnt
zroot/sys/tmp             96K  28.8G    96K  /mnt/tmp
zroot/sys/usr            288K  28.8G    96K  /mnt/usr
zroot/sys/usr/ports       96K  28.8G    96K  /mnt/usr/ports
zroot/sys/usr/src         96K  28.8G    96K  /mnt/usr/src
zroot/sys/var            584K  28.8G   104K  /mnt/var
zroot/sys/var/audit       96K  28.8G    96K  /mnt/var/audit
zroot/sys/var/crash       96K  28.8G    96K  /mnt/var/crash
zroot/sys/var/log         96K  28.8G    96K  /mnt/var/log
zroot/sys/var/mail        96K  28.8G    96K  /mnt/var/mail
zroot/sys/var/tmp         96K  28.8G    96K  /mnt/var/tmp

MBR用ブートコードの設定

zpool set bootfs=zroot/sys/ROOT/default zroot
gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 2 da0

EFI用ブートローダの設定

ESPをFATでフォーマットして/tmp/espにマウント。

# newfs_msdos -F 32 da0p1
# mkdir /tmp/esp
# mount -t msdosfs /dev/da0p1 /tmp/esp

「newfs_msdos: 32750 clusters too few clusters for FAT32, need 65525」って感じのエラーになるときは、newfs_msdosでセクタサイズ/クラスタサイズを明示的に指定してやる。条件はよくわからないが、16KiBクラスタとかでフォーマットしようとする事があるっぽい。

# newfs_msdos -F 32 -S 512 -c 4 da0p1

-Sがセクタサイズ(バイト)で、-cがクラスタサイズ(セクタ数)を表す。上記例だと1クラスタ=512バイトセクタ×4=4096バイト、ということになる。

ブートローダをコピー

# mkdir -p /tmp/esp/efi/boot
# cp /boot/boot1.efi /tmp/esp/efi/boot/BOOTx64.efi

(2021-01-12追記)
以前の説明ではESPにloader.rcを作っていたが、効果がないので記述を削除。また、12.0-RELEASEからBOOTx64.efiとしてboot1.efiに代わってloader.efiが使われるようになっている。

ファイルが正しい場所にあるか確認

# ( cd /tmp/esp && find . )
.
./efi
./efi/boot
./efi/boot/BOOTx64.efi

最後に必ずアンマウントする

# umount /tmp/esp

ここまで来たら終ったも同然。shellをexitし、通常のインストール手順で「Partitioning」まで進める。

「Shell」に入り、そのままexitするとシステムのインストールが行われる。

タイムゾーンやデフォルトのデーモンの設定なども通常通り行い、最後の「Manual Configuration」でシェルに入り、最後の仕上げをする。

シェルの先頭メッセージにある通り、インストール先ディレクトリにchrootした状態、つまりインストーラ環境の/mntが/になっているので注意。

スワップの設定

# vi /etc/fstab
# Device        Mountpoint      FStype  Options Dump    Pass#
/dev/da0p4      none            swap    sw      0       0

/boot/loader.confの設定

# echo 'zfs_load="YES"' >> /boot/loader.conf

/etc/rc.confの設定

# echo 'zfs_enable="YES"' >> /etc/rc.conf

設定が全て終わったらシェルをexitしてRebootする。

再起動後、無事ログインプロンプトが出ればひとまず成功。まずはrootでログインし、ファイルシステム群が想定通りにマウントされているか十分に確認すること。特にホームディレクトリを別プールとした場合は、/usr/homeが正常に機能しているか確認してくだしあ。

お疲れ様でした。

  • FreeBSD 8.3-RELEASEから、デフォルトchecksumはfletcher4になったので、今や明示的に指定する必要はない。
  • vfs.root.mountfromによるルートプールの設定も必要なくなったっぽい。
  • freebsd/install/install_freebsd_11_1_by_manually_zfs_partitioning.txt
  • 最終更新: 2022-05-16 16:36
  • by Decomo