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が全部やってくれる。
操作は全てインストーラのシェルで行う。
ZFSモジュールを読み込む
# 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
FSの確認とブートコードの書き込み
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
FreeBSD Installerでシステムをインストール
ここまで来たら終ったも同然。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によるルートプールの設定も必要なくなったっぽい。