vm-bhyveとZFSを使って効率的にNetBSD仮想マシンを管理する
ZFSはファイルシステムの一種で、ファイルシステムの差分バックアップやロールバックを簡単に操作できます。
ZFS上で仮想マシン(VM)のディスクを管理すると、ゲストOSがZFSをサポートしていなくてもシステム全体がZFSの恩恵を受けられます。なにかVM内で注意を要する作業をおこなうとき、あらかじめホスト側でディスクのスナップショットを控えておけば、VM内のシステムが壊れても簡単に以前の状態へ復旧できます。
毎日、あるいは毎週高い頻度でNetBSDのcurrentを追跡する場合を考えてみましょう。物理マシンにではなくVMへNetBSDをインストールしているものとします。build.sh
から最新のカーネルとユーザランドをビルドしました。そしてインストールして再起動すると……カーネルがpanicしたりユーザランドが一部壊れていたり、pkgsrcからインストールしたソフトウェアがcoreを吐いたりするかもしれません。このようなときは原因究明のために調査が必要ですが、以前の「問題がない」状態へ切り戻すことも常に選択肢に含んでおきたいものです。アップデートする前にホスト側でスナップショットを取っておけばそれも可能となります。
ここではホストOSをFreeBSD 12.1/amd64とし、VMの管理・操作はvm-bhyveからおこない、ファイルシステムはZFSとして効率の良いNetBSD current追跡方法を紹介します。
vm-bhyveを使いスナップショットを取る
vm-bhyveはBhyveのユーザインタフェースのひとつです。bhyve(8)
やbhyvectl(8)
と比べ短く少ないオプションでVMを操作できます。ZFSにも対応しており、同じUIからVMのスナップショット/ロールバックを操作できます。
インストール方法はREADMEのQuick-Startを参考にしてください。インストール後、次に示すようにNetBSDのVMを作成しインストールまで完了したとします。
vm list
NAME DATASTORE LOADER CPU MEMORY VNC AUTOSTART STATE
NetBSD default grub 6 8192M - No Stopped
ここで、vm snapshot <VM名[@スナップショット名]>
を使い現時点でのスナップショットを取得します。スナップショットの名前にはNetBSDのバージョン番号をつけます。
vm snapshot NetBSD@8.1
zfs list -t snap
してスナップショットの一覧を表示すると以下のようになります。
$ zfs list -t snap
NAME USED AVAIL REFER MOUNTPOINT
zroot/vm/NetBSD@8.1 360M - 629M -
これでなにかVMのディスクに変更を加えても、この時点の状態へロールバックできるようになりました。もし同じバージョンで複数のスナップショットを取りたいときは、vm snapshot NetBSD@8.1_20200111
といった具合でバージョン番号に加えて日付をつけるといいでしょう。
ホストOSでbuild.shを実行する
Bhyveを使っているならゲストOSよりホストOSのほうが高速にビルドできます。ここではゲストOS上でbuild.sh
するのではなく、ホストOS上でbuild.sh
を動かしNetBSDカーネルとユーザランドをクロスビルドします。リポジトリのHEADを常に追いかける者として、複数の環境に対応したクロスビルドの仕組みはたいへん有益です。
NetBSD上でなくともbuild.sh
の実行方法は変わりません。toolsを作り、kernelとdistributionをビルドしてください。以下は一例です。
cd path/to/netbsd/src
cvs update -dP
./build.sh -O ../obj -T ../tools -X ../xsrc -x -j11 -U tools
./build.sh -O ../obj -T ../tools -X ../xsrc -x -j11 -U kernel=GENERIC
./build.sh -O ../obj -T ../tools -X ../xsrc -x -j11 -U distribution
仮想ディスクのマウント先へNetBSDをインストールする
build.sh
は指定したディレクトリ下へNetBSDユーザランドをインストールできます。ビルド環境とアップデート対象が同一ならbuild.sh ... install=/
といったように実行するのですが、今回はアップデート対象がVMです。そこでVMの仮想ディスクをホストOSにマウントし、マウントポイントへ向けてこのコマンドを実行します。
vm-bhyve
は標準でdisk0.imgというrawディスクイメージを作成します。FreeBSDでこのrawイメージをマウントするには、mdconfig(8)
でメモリディスクを作ってからそのデバイスをマウントするという手順を踏みます。たとえば/zroot/vm/NetBSD/disk0.img
を/dev/md0
として、/mnt
へマウントするには次のようにコマンドを実行します。
mdconfig -u md0 -f /zroot/vm/NetBSD/disk0.img
mount /dev/md0s1 /mnt
このあと/mnt
の中身を確認すると、たしかにNetBSDルートファイルシステムがマウントされています。
ls /mnt
.cshrc bin cdrom kern libexec netbsd.old root tmp
.profile boot dev lib mnt proc sbin usr
altroot boot.cfg etc libdata netbsd rescue stand var
ではこのディレクトリへめがけて、さきほどビルドしたNetBSDバイナリをインストールしましょう。
cd path/to/netbsd/src
./build.sh -O ../obj -T ../tools -X ../xsrc -x -j11 -U install=/mnt
mv /mnt/netbsd /mnt/netbsd.old
cp ../obj/sys/arch/amd64/compile/GENERIC/netbsd /mnt/netbsd
インストール後はアンマウントします。通常のumount(8)
をしたあと、mdconfig(8)
でメモリディスクをデタッチします。
umount /mnt
mdconfig -d -u md0
おわりに
以上の操作をしたあと、vm start NetBSD
するとbuild.sh
でビルドしたカーネルとユーザランドが使えるようになっています。もしなにか問題があるようならvm rollback NetBSD@8.1
のようにしてロールバックすればいいのです。
ロールバックが簡単にできるので物理マシンでは怖くてできないような操作や実験も気軽にできるようになります。vm-bhyveでは復旧のみならず、VMの複製もvm clone
でできます。開発者にとって最高のサンドボックスです。
一方で作業ミスが許されない操作もあるため、アップデートは手作業ではなくシェルスクリプトを書いて自動化するのが望ましいです。特にbuild.sh ... install=/mnt
はインストール先の指定を間違えるとホストOS側を破壊しかねません。もっとも、速度を気にしないならゲストOS内でアップデート作業をしたほうがいいでしょう。