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追跡方法を紹介します。

  1. vm-bhyveを使いスナップショットを取る
  2. ホストOSでbuild.shを実行する
  3. 仮想ディスクのマウント先へNetBSDをインストールする
  4. おわりに

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内でアップデート作業をしたほうがいいでしょう。