22.6.使用 FreeBSD 上的 bhyve 虚拟机

BSD 许可的 bhyve 虚拟机管理器随着 FreeBSD 10.0-RELEASE 已经成为了底层系统的一部分。这个虚拟机管理器支持数种客户机,包括 FreeBSD,OpenBSD 和数个 Linux® 发行版。默认情况下,bhyve 提供对串行控制台的访问而不模拟图形化控制台。其利用较新的 CPU 上的 virtualization offload 功能来避免使用过时方法翻译指令和手动管理内存映射。

bhyve 的设计需要支持 Intel® Extended Page Tables(EPT)或 AMD® Rapid Virtualization Indexing(RVI)或 Nested Page Tables(NPT)的 CPU。以超过一枚 vCPU 运行 Linux 或者 FreeBSD 客户机需要 VMX unrestricted 模式支持(UG)。大多数新的处理器,特别是 Intel® Core™ i3/i5/i7 和 Intel® Xeon™ E3/E5/E7 都支持这些功能。对 UG 的支持是从 Intel® 的 Westmere 微架构引入的。若要查阅一份完整的支持 EPT 的 Intel® 处理器列表,请参见 https://ark.intel.com/content/www/us/en/ark/search/featurefilter.html?productType=873&0_ExtendedPageTables=Trueopen in new window。RVI 在第三代以及之后的 AMD Opteron™(Barcelona)处理器中应用。判断处理器是否支持 bhyve 的方法是运行 demsg,或者在 /var/run/dmesg.boot 中的 Feature2 一行查找 POPCNT 处理器功能标识(针对 AMD® 处理器);或者在 VT-x 一行查找 EPTUG 处理器功能标识(针对 Intel® 处理器)。

22.6.1. 准备宿主机

在 bhyve 中创建虚拟机的第一步是配置宿主操作系统。首先,加载 bhyve 内核模块:

# kldload vmm

然后,创建 tap 介面以供虚拟机中的网络设备进行连接。为了让该网络设备加入网络,另外创建一个桥接介面,其中包含 tap 介面和物理网络介面作为成员。在下面的例子中,物理网络介面为 igb0

# ifconfig tap0 create
# sysctl net.link.tap.up_on_open=1
net.link.tap.up_on_open: 0 -> 1
# ifconfig bridge0 create
# ifconfig bridge0 addm igb0 addm tap0
# ifconfig bridge0 up

22.6.2. 创建一个 FreeBSD 客户机

创建一个文件用作客户机的虚拟磁盘。指定这个虚拟磁盘的大小和名称:

# truncate -s 16G guest.img

下载 FreeBSD 的安装镜像:

# fetch ftp://ftp.freebsd.org/pub/FreeBSD/releases/ISO-IMAGES/12.2/FreeBSD-12.2-RELEASE-amd64-bootonly.iso
FreeBSD-12.2-RELEASE-amd64-bootonly.iso       100% of  230 MB  570 kBps 06m17s

FreeBSD 附带了一个在 bhyve 中运行虚拟机的示例脚本。这个脚本将会启动虚拟机并循环执行,所以将在其崩溃时自动重新启动。这个脚本可接受数个选项来配置虚拟机:-c 控制虚拟 CPU 的数量,-m 限制客户机的可用内存,-t 定义使用的 tap 设备,-d 指定其使用的磁盘镜像,-i 控制 bhyve 从 CD 镜像引导,而非从磁盘引导,-I 指定要使用的 CD 镜像。最后一个参数是虚拟机的名称,该名称将被用来追踪运行中的虚拟机。这个例子将在安装模式下启动虚拟机:

# sh /usr/share/examples/bhyve/vmrun.sh -c 1 -m 1024M -t tap0 -d guest.img -i -I FreeBSD-12.2-RELEASE-amd64-bootonly.iso guestname

这个虚拟机将会引导并启动安装器。在虚拟机中完成系统安装并进入最后阶段,当系统提示是否进入 shell 时,选择 Yes

重新启动虚拟机。重启会导致 bhyve 退出,这时循环执行 bhyvevmrun.sh 脚本会自动重启虚拟机。这时请从引导器菜单中选择重启来跳出循环。之后,客户机就可以从虚拟磁盘中启动了:

# sh /usr/share/examples/bhyve/vmrun.sh -c 4 -m 1024M -t tap0 -d guest.img guestname

22.6.3. 创建一个 Linux® 客户机

要引导进入 FreeBSD 以外的系统,必须先安装 sysutils/grub2-bhyveopen in new window port。

接下来,创建一个文件用作客户机的虚拟磁盘:

# truncate -s 16G linux.img

使用 bhyve 启动虚拟机分为两个步骤。首先要加载一个内核,然后启动客户机。Linux® 内核通过 sysutils/grub2-bhyveopen in new window 加载。创建 device.map 令 grub 将虚拟设备映射到宿主机上的镜像文件:

(hd0) ./linux.img
(cd0) ./somelinux.iso

使用 sysutils/grub2-bhyveopen in new window 将 Linux® 内核从 ISO 文件中加载:

# grub-bhyve -m device.map -r cd0 -M 1024M linuxguest

这将启动 grub。如果安装 CD 中包含 grub.cfg,将会显示一个菜单;否则你需要手动指明并加载 vmlinuzinitrd 文件:

grub> ls
(hd0) (cd0) (cd0,msdos1) (host)
grub> ls (cd0)/isolinux
boot.cat boot.msg grub.conf initrd.img isolinux.bin isolinux.cfg memtest
splash.jpg TRANS.TBL vesamenu.c32 vmlinuz
grub> linux (cd0)/isolinux/vmlinuz
grub> initrd (cd0)/isolinux/initrd.img
grub> boot

现在 Linux® 内核就加载完毕了,可以启动客户机:

# bhyve -A -H -P -s 0:0,hostbridge -s 1:0,lpc -s 2:0,virtio-net,tap0 -s 3:0,virtio-blk,./linux.img \
    -s 4:0,ahci-cd,./somelinux.iso -l com1,stdio -c 4 -m 1024M linuxguest

系统将会引导进入并启动安装器。在虚拟机中完成系统安装之后,重新启动虚拟机。bhyve 会在这时退出。请先销毁这个虚拟机实例,然后重新启动:

# bhyvectl --destroy --vm=linuxguest

现在客户机可以直接从磁盘镜像中启动了。首先加载内核:

# grub-bhyve -m device.map -r hd0,msdos1 -M 1024M linuxguest
grub> ls
(hd0) (hd0,msdos2) (hd0,msdos1) (cd0) (cd0,msdos1) (host)
(lvm/VolGroup-lv_swap) (lvm/VolGroup-lv_root)
grub> ls (hd0,msdos1)/
lost+found/ grub/ efi/ System.map-2.6.32-431.el6.x86_64 config-2.6.32-431.el6.x
86_64 symvers-2.6.32-431.el6.x86_64.gz vmlinuz-2.6.32-431.el6.x86_64
initramfs-2.6.32-431.el6.x86_64.img
grub> linux (hd0,msdos1)/vmlinuz-2.6.32-431.el6.x86_64 root=/dev/mapper/VolGroup-lv_root
grub> initrd (hd0,msdos1)/initramfs-2.6.32-431.el6.x86_64.img
grub> boot

引导进入虚拟机:

# bhyve -A -H -P -s 0:0,hostbridge -s 1:0,lpc -s 2:0,virtio-net,tap0 \
    -s 3:0,virtio-blk,./linux.img -l com1,stdio -c 4 -m 1024M linuxguest

虚拟机中的 Linux® 将会启动并提示你登录。当你不再使用虚拟机时,重新启动虚拟机来退出 bhyve,并销毁虚拟机实例:

# bhyvectl --destroy --vm=linuxguest

22.6.4. 使用 UEFI 固件引导 bhyve 虚拟机

除了 bhyveload 和 grub-bhyve,bhyve 虚拟机管理器还可使用 UEFI 用户态固件来引导虚拟机。这可能兼容其他引导器不支持的客户机操作系统。

要利用 bhyve 的 UEFI 支持,首先要生成 UEFI 固件镜像。你可以通过安装 sysutils/bhyve-firmwareopen in new window 的 port 或 二进制软件包来实现。

准备好固件之后,向 bhyve 命令添加标识 -l bootrom,/path/to/firmware,例如:

# bhyve -AHP -s 0:0,hostbridge -s 1:0,lpc \
-s 2:0,virtio-net,tap1 -s 3:0,virtio-blk,./disk.img \
-s 4:0,ahci-cd,./install.iso -c 4 -m 1024M \
-l bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd \
guest

sysutils/bhyve-firmwareopen in new window 还包含了启用 CSM 的固件,若要在 legacy BIOS 模式中启动不支持 UEFI 的客户机,请这样运行:

# bhyve -AHP -s 0:0,hostbridge -s 1:0,lpc \
-s 2:0,virtio-net,tap1 -s 3:0,virtio-blk,./disk.img \
-s 4:0,ahci-cd,./install.iso -c 4 -m 1024M \
-l bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI_CSM.fd \
guest

22.6.5. 为客户机设置图形化 UEFI Framebuffer

UEFI 固件支持对主要使用图形化界面的客户机操作系统格外有用,例如 Microsoft Windows®。

对 UEFI-GOP framebuffer 的支持也可以用标识 -s 29,fbuf,tcp=0.0.0.0:5900 来启用。framebuffer 的分辨率可以通过如 w=800 h=600 来设置。bhyve 也可以通过添加 wait 来等待 VNC 连接,之后再引导进入客户机。framebuffer 可以从宿主机或者 VNC 协议的网络连接访问。此外,可以添加 -s 30,xhci,tablet 来实现与宿主机之间精确的鼠标同步。

最后的 bhyve 命令可能类似这样:

# bhyve -AHP -s 0:0,hostbridge -s 31:0,lpc \
-s 2:0,virtio-net,tap1 -s 3:0,virtio-blk,./disk.img \
-s 4:0,ahci-cd,./install.iso -c 4 -m 1024M \
-s 29,fbuf,tcp=0.0.0.0:5900,w=800,h=600,wait \
-s 30,xhci,tablet \
-l bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd \
guest

提示:

在模拟 BIOS 模式下,当控制从固件移交到宿主机操作系统后,framebuffer 会停止接收更新。

22.6.6. 在 bhyve 客户机中使用 ZFS

如果在宿主机上可以使用 ZFS,在客户机上使用 ZFS 卷取代磁盘镜像可以显著提高性能。你可以这样新建一个 ZFS 卷:

# zfs create -V16G -o volmode=dev zroot/linuxdisk0

启动虚拟机时,指定 ZFS 卷作为磁盘驱动器:

# bhyve -A -H -P -s 0:0,hostbridge -s 1:0,lpc -s 2:0,virtio-net,tap0 -s3:0,virtio-blk,/dev/zvol/zroot/linuxdisk0 \
    -l com1,stdio -c 4 -m 1024M linuxguest

22.6.7. 虚拟机控制台

你可以使用类似于 sysutils/tmuxopen in new window 或者 sysutils/screenopen in new window 这样的管理工具将 bhyve 控制台封装在一个会话中用来连接和断开控制台,这将带来一些好处。你还可以将一个空的调制解调器作为 bhyve 的控制台,然后使用 cu 来访问。若要这样做,请加载 nmdm 内核模块,然后将 -l com1,stdio 替换为 -l com1,/dev/nmdm0A。设备 /dev/nmdm 会自动按需创建并组成一对,对应着空的调制解调器的两端(/dev/nmdm0A/dev/nmdm0B)。查阅 nmdm(4) 获取更多信息。

# kldload nmdm
# bhyve -A -H -P -s 0:0,hostbridge -s 1:0,lpc -s 2:0,virtio-net,tap0 -s 3:0,virtio-blk,./linux.img \
    -l com1,/dev/nmdm0A -c 4 -m 1024M linuxguest
# cu -l /dev/nmdm0B
Connected

Ubuntu 13.10 handbook ttyS0

handbook login:

22.6.8. 管理虚拟机

对于每个虚拟机,在 /dev/vmm 下都会创建一个设备节点。这使得管理员很容易就能看到运行中的虚拟机列表:

# ls -al /dev/vmm
total 1
dr-xr-xr-x   2 root  wheel    512 Mar 17 12:19 ./
dr-xr-xr-x  14 root  wheel    512 Mar 17 06:38 ../
crw-------   1 root  wheel  0x1a2 Mar 17 12:20 guestname
crw-------   1 root  wheel  0x19f Mar 17 12:19 linuxguest
crw-------   1 root  wheel  0x1a1 Mar 17 12:19 otherguest

通过 bhyvectl 可以销毁指定的虚拟机:

# bhyvectl --destroy --vm=guestname

22.6.9. 持久化配置

要配置系统在启动时运行 bhyve 虚拟机,请进行如下配置:

  1. /etc/sysctl.conf

    net.link.tap.up_on_open=1
    
  2. /etc/rc.conf

    cloned_interfaces="bridge0 tap0"
    ifconfig_bridge0="addm igb0 addm tap0"
    kld_list="nmdm vmm"