bhyveはFreeBSDで動く、つまりType 2のハイパーバイザ。

FreeBSDにはjailがある。
jailのいいところは、カーネルを共有しつつユーザランドだけ分けることで、オーバーヘッドを抑えられるところ。
悪いところはOSに制限が発生するところ。要するにLinuxやWindows、FreeBSDでも他のバージョンを動かせないところ。

仮想化は何かの目的、たとえばアプリケーションを動かすためのもので、いまどきOS依存のアプリケーションは少ない。
とはいうものの、FreeBSDは年々、本体はともかく裾野のリソースが先細りで、ports/packageがなくなったり、あったとしても情報は少なくて、まるっとLinuxごと動かしたいなと感じることがある。
もちろんWindowsについては当然FreeBSDでは動かないアプリなんて山ほどある。

そういった点では、用途に合わせて最適なOS(とアプリケーション)を使い慣れたFreeBSD上で動かせるのはかなりのメリット。
というのも、バックアップが簡単にできるからである。
ZFS上にイメージを作れば、スナップショットにロールバックはお手の物である。
壊し放題である。
ESXiなどのType 1ハイパーバイザでは、これができない。できるかもしれないけど知らない。

Windowsを物理PC上で使っていて、壊れたとする。バックアップがあったとしても、復旧が面倒。
Linuxについてはバックアップからの復旧は比較的簡単だが、俺様なんか滅多にLinuxを使わなくて操作をすぐ忘れるという点でやはり復旧が面倒。

以上のような背景があったところに、このたび宅鯖をハードウェア仮想化対応のCPUに変えたので、遅まきながらbhyveを導入する。
以下ではWindows10をインストールする。

まずはvm-bhyveを

bhyveの導入には、まず公式のFreeBSD handbookを参照するが、いろいろと面倒くさそうである。
https://www.freebsd.org/doc/handbook/virtualization-host-bhyve.html

遅れて導入すると、いろいろと環境が整っているものである。
bhyveの場合には、vm-bhyveというツールがあればこのへんは一挙解決。
virtualboxを使ったことがあれば、それをイメージしながら進めると理解しやすい。

ただ後述するが、Windowsのイメージそのものにはzfsボリュームを使えない。(ZFS上にイメージを置くことはできる)
https://github.com/churchers/vm-bhyve
https://github.com/churchers/vm-bhyve/wiki/Running-Windows

大きな流れ

  1. vm-bhyveのインストール
  2. 初期設定
  3. 初期設定(ネットワーク)
  4. 仮想マシンインストール準備(インストーラ = ISO)
  5. 仮想マシンインストール準備(仮想マシン設定)【次回】
  6. 仮想マシンインストール【次回】

vm-bhyveのインストール

pkgでインストールできる。
vm-bhyveのほか、仮想OS用のfirmwareもインストールしておく。

$ sudo pkg install vm-bhyve
FreeBSD repository update completed. 31790 packages processed.
All repositories are up to date.
The following 1 package(s) will be affected (of 0 checked):

New packages to be INSTALLED:
        vm-bhyve: 1.2.3

Number of packages to be installed: 1

55 KiB to be downloaded.
[ex01] [1/1] Fetching vm-bhyve-1.2.3.txz: 100%   55 KiB  56.3kB/s    00:01
Checking integrity... done (0 conflicting)
[ex01] [1/1] Installing vm-bhyve-1.2.3...
[ex01] [1/1] Extracting vm-bhyve-1.2.3: 100%
Message from vm-bhyve-1.2.3:

To enable vm-bhyve, please add the following lines to rc.conf,
depending on whether you are using ZFS storage or not. Please note
that the directory or dataset specified should already exist.

    vm_enable="YES"
    vm_dir="zfs:pool/dataset"

OR

    vm_enable="YES"
    vm_dir="/directory/path"

Then run 'vm init'.

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Please note, if upgrading from version 1.1, it is advised to shutdown guests
and restart the host in order to re-create all virtual switches using new identifiers.

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

どんなファイルがインストールされたかは、pkg listで確認できる。
コマンドとしては/usr/local/sbin/vmを使う。
実行にはroot権限が必要。
service -lで表示されるサービス名もvm。

$ pkg list vm-bhyve
/usr/local/etc/rc.d/vm
/usr/local/lib/vm-bhyve/vm-cmd
/usr/local/lib/vm-bhyve/vm-config
/usr/local/lib/vm-bhyve/vm-core
/usr/local/lib/vm-bhyve/vm-datastore
/usr/local/lib/vm-bhyve/vm-guest
/usr/local/lib/vm-bhyve/vm-info
/usr/local/lib/vm-bhyve/vm-migration
/usr/local/lib/vm-bhyve/vm-rctl
/usr/local/lib/vm-bhyve/vm-run
/usr/local/lib/vm-bhyve/vm-switch
/usr/local/lib/vm-bhyve/vm-switch-manual
/usr/local/lib/vm-bhyve/vm-switch-standard
/usr/local/lib/vm-bhyve/vm-switch-vale
/usr/local/lib/vm-bhyve/vm-switch-vxlan
/usr/local/lib/vm-bhyve/vm-util
/usr/local/lib/vm-bhyve/vm-zfs
/usr/local/man/man8/vm.8.gz
/usr/local/sbin/vm
/usr/local/share/examples/vm-bhyve/alpine.conf
/usr/local/share/examples/vm-bhyve/arch.conf
/usr/local/share/examples/vm-bhyve/centos6.conf
/usr/local/share/examples/vm-bhyve/centos7.conf
/usr/local/share/examples/vm-bhyve/config.sample
/usr/local/share/examples/vm-bhyve/coreos.conf
/usr/local/share/examples/vm-bhyve/debian.conf
/usr/local/share/examples/vm-bhyve/default.conf
/usr/local/share/examples/vm-bhyve/dragonfly.conf
/usr/local/share/examples/vm-bhyve/freebsd-zvol.conf
/usr/local/share/examples/vm-bhyve/freepbx.conf
/usr/local/share/examples/vm-bhyve/netbsd.conf
/usr/local/share/examples/vm-bhyve/openbsd.conf
/usr/local/share/examples/vm-bhyve/resflash.conf
/usr/local/share/examples/vm-bhyve/ubuntu.conf
/usr/local/share/examples/vm-bhyve/windows.conf
/usr/local/share/licenses/vm-bhyve-1.2.3/BSD2CLAUSE
/usr/local/share/licenses/vm-bhyve-1.2.3/LICENSE
/usr/local/share/licenses/vm-bhyve-1.2.3/catalog.mk


$ sudo pkg install bhyve-firmware
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
All repositories are up to date.
The following 3 package(s) will be affected (of 0 checked):

New packages to be INSTALLED:
        bhyve-firmware: 1.0_1
        uefi-edk2-bhyve-csm: 0.2_1,1
        uefi-edk2-bhyve: 0.2_1,1

Number of packages to be installed: 3

The process will require 4 MiB more space.
1 MiB to be downloaded.
[ex01] [1/3] Fetching bhyve-firmware-1.0_1.txz: 100%    496 B   0.5kB/s    00:01
[ex01] [2/3] Fetching uefi-edk2-bhyve-csm-0.2_1,1.txz:   2%   16 KiB  16.4kB/s  [ex01] [2/3] Fetching uefi-edk2-bhyve-csm-0.2_1,1.txz: 100%  760 KiB 778.7kB/s    00:01
[ex01] [3/3] Fetching uefi-edk2-bhyve-0.2_1,1.txz:  59%  440 KiB 450.6kB/s    00[ex01] [3/3] Fetching uefi-edk2-bhyve-0.2_1,1.txz: 100%  740 KiB 757.6kB/s    00:01
Checking integrity... done (0 conflicting)
[ex01] [1/3] Installing uefi-edk2-bhyve-csm-0.2_1,1...
[ex01] [1/3] Extracting uefi-edk2-bhyve-csm-0.2_1,1: 100%
[ex01] [2/3] Installing uefi-edk2-bhyve-0.2_1,1...
[ex01] [2/3] Extracting uefi-edk2-bhyve-0.2_1,1: 100%
[ex01] [3/3] Installing bhyve-firmware-1.0_1...

仮想マシン他置き場を作る

もちろんZFSで作るよな。
ここで作った置き場には、仮想マシンのほか、ISOイメージ、テンプレート、すべての仮想マシンに共通の設定ファイルが置かれる。
ルート直下に/vmを作った。
なお本記事で"$vm_dir"と記載をする場合にはこの仮想マシン置き場を指す。

$ sudo zfs create zroot/vm
$ sudo mkdir /vm
$ sudo zfs set mountpoint=/vm zroot/vm
$ zfs list
NAME                 USED  AVAIL  REFER  MOUNTPOINT
zroot               6.73G   216G    88K  /zroot
(略)
zroot/vm              88K   216G    88K  /zroot/vm

vm-bhyveの初期設定

まず/etc/rc.confへの書き込み。
ホスト起動時にvm-bhyveも起動するように。
また、先に作った仮想マシン置き場をvm-bhyveに知らせるために。

$ sudo sysrc vm_enable="YES"
vm_enable:  -> YES
$ sudo sysrc vm_dir="zfs:zroot/vm"
vm_dir:  -> zfs:zroot/vm

次にvm init。仮想マシン置き場にいろいろとファイル/ディレクトリが作られるとともに、必要なカーネルモジュールがロードされる。
vm initはホストが起動する都度、実行される必要がある。
この場合、vm initはカーネルモジュールのロードと、ネットワーク設定(tap)を行う。
/etc/rc.confにvm_enableをしてあれば、気にする必要なない。

$ sudo vm init
$

$ ls -la /vm
total 35
drwxr-xr-x   6 root  wheel   6 May  4 20:34 .
drwxr-xr-x  20 root  wheel  26 May  6 15:03 ..
drwxr-xr-x   2 root  wheel   4 May  3 18:40 .config
drwxr-xr-x   2 root  wheel   5 May  4 22:48 .iso
drwxr-xr-x   2 root  wheel  18 May  3 18:46 .templates

$ kldstat
Id Refs Address                Size Name
 1   28 0xffffffff80200000  243cd00 kernel
 2    1 0xffffffff8263e000   3a9a10 zfs.ko
 3    2 0xffffffff829e8000     a4f0 opensolaris.ko
 4    1 0xffffffff82c21000     2678 intpm.ko
 5    1 0xffffffff82c24000      b10 smbus.ko
 6    1 0xffffffff82c25000   537460 vmm.ko
 7    1 0xffffffff8315d000      b30 nmdm.ko
 8    1 0xffffffff8315e000     6fb3 if_bridge.ko
 9    1 0xffffffff83165000     4410 bridgestp.ko
10    1 0xffffffff8316a000     2e77 if_tap.ko

仮想マシン置き場に、OSごとのテンプレートファイルもコピーする。
/usr/local/share/examples/vm-bhyve/にあるやつね。(さきほどpkg infoでも出てきた)

$ sudo cp /usr/local/share/examples/vm-bhyve/* /vm/.templates/
$ ls /vm/.templates/
alpine.conf             config.sample           dragonfly.conf          openbsd.conf
arch.conf               coreos.conf             freebsd-zvol.conf       resflash.conf
centos6.conf            debian.conf             freepbx.conf            ubuntu.conf
centos7.conf            default.conf            netbsd.conf             windows.conf

以上で初期設定終わり。
つぎは初期設定(ネットワーク)

初期設定(ネットワーク)

仮想マシン用ネットワークの結線を行う。
まず、仮想マシンの繋がる仮想スイッチを作り、仮想スイッチとホストマシンのネットワークインタフェースを繋ぐ。

外界 <--> ホストのインタフェース <--> 仮想スイッチ
というネットワークを作る。

先々、仮想マシンを作ると
外界 <--> ホストのインタフェース <--> 仮想スイッチ <--> 仮想マシン
というネットワークになる。
仕組み的なことをいうと、仮想スイッチはbridgeで、仮想マシンのインタフェースはtapになる。

以下の例では、publicという名前の仮想スイッチ(オプションなしでのcreateなのでbridgeインタフェース)を作成している。
名前は、vm-bhyveのテンプレートで仮想スイッチを"public"にしているからで、気に入らなければ別の名前でもよい。
# その場合は$vm_dir/.templatesにあるファイルを書き換えておくとよい。
addで仮想スイッチに物理インタフェースを追加。
物理インタフェースは、もちろんのことホストマシンのインタフェースに合わせること。 また、これも当たり前だけど、追加するインタフェースはインターネットに向いている方にしような。
試しにやってみたら、wlan0でも行けたわ。

$ sudo vm switch create public
$ sudo vm switch add public re0
$ ifconfig
re0: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> metric 0 mtu 1500
        options=8209b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM,WOL_MAGIC,LINKSTATE>
        ether 6c:4b:90:a6:13:23
        inet 192.168.1.7 netmask 0xffffff00 broadcast 192.168.1.255
        media: Ethernet autoselect (1000baseT )
        status: active
        nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384
        options=680003<RXCSUM,TXCSUM,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6>
        inet6 ::1 prefixlen 128
        inet6 fe80::1%lo0 prefixlen 64 scopeid 0x2
        inet 127.0.0.1 netmask 0xff000000
        groups: lo
        nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
vm-public: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
        ether 26:ad:45:ea:0c:c3
        id 00:00:00:00:00:00 priority 32768 hellotime 2 fwddelay 15
        maxage 20 holdcnt 6 proto rstp maxaddr 2000 timeout 1200
        root id 00:00:00:00:00:00 priority 32768 ifcost 0 port 0
        member: re0 flags=143<LEARNING,DISCOVER,AUTOEDGE,AUTOPTP>
                ifmaxaddr 0 port 1 priority 128 path cost 20000
        groups: bridge vm-switch viid-4c918@
        nd6 options=1

これで以下のようなネットワーク構成になった。
外界 <--> ホストのインタフェース(re0) <--> 仮想スイッチ(vm-public)

これですべての初期設定が完了。