bhyve快速起步

主机准备

内核vmm

bhyve 创建虚拟机之前需要加载加载 bhyve 内核模块:

加载内核模块
kldload vmm
kldload nmdm
kldload if_tap
kldload if_bridge

并且确保启动时加载内核模块:

配置启动时加载模块
echo 'vmm_load="YES"' >> /boot/loader.conf
echo 'nmdm_load="YES"' >> /boot/loader.conf
echo 'if_tap_load="YES"' >> /boot/loader.conf
echo 'if_bridge_load="YES"' >> /boot/loader.conf

创建网桥和tap

比较简单的虚拟机网络设置是为虚拟机内部的网络设备创建一个连接的 tap 接口,然后在host主机上创建一个 bridge 接口,并通过 bridge 接口来包含 tap 接口和 物理网卡 接口作为 members 。这样实现的虚拟网络就类似于Linux KVMlibvirt 网桥型网络

备注

第一次实践是,由于我在 FreeBSD无线网络BCM43602(通过wifibox) 使用了 wifibox ,实际上已经启动了 tap 设备以及虚拟化,并且也具备了 bridge 网桥。

不过,我再次实践时重新安装了一台FreeBSD服务器,实践本段 创建网桥和tap

  • /etc/sysctl.conf 中配置tap设备在操作系统启动时启动:

配置tap设备启动
echo "net.link.tap.up_on_open=1" >> /etc/sysctl.conf
sysctl net.link.tap.up_on_open=1
  • 创建网桥并连接网卡( 案例中使用的网卡设备是 igc0 )

创建网桥并连接网卡
# 创建tap设备
ifconfig tap0 create
# 创建多个tap设备,分别对应不同虚拟机内部虚拟网卡,规划为每个vm一个虚拟网卡设备,这里案例我一共添加了3个tap设备
ifconfig tap1 cteate
ifconfig tap2 cteate

# 创建 bridge0
ifconfig bridge0 create

# 网桥重命名为 igc0bridge
ifconfig bridge0 name igc0bridge
ifconfig igc0bridge up

# 可以连续使用 addm 添加多个设备到网桥,也可以拆分成一次addm一个设备
# 添加tap虚拟网卡设备连接到bridge
ifconfig bridge0 addm tap0 addm tap1 addm tap2
# 一共有4个Intel i226-v 2.5Gbps网卡,都配置到一个bridge上联通网络
ifconfig bridge0 addm igc0 addm igc1 addm igc2 addm igc3

# 现在虚拟网络和物理网卡接口就已经实现了完全的交换网络(平面型),可以测试网络连通性了
  • 确保启动时激活:

/etc/rc.conf 中配置
# 创建网桥以及用于虚拟机的tap虚拟网络设备
cloned_interfaces="bridge0 tap0 tap1 tap2"
# 重命名网桥
ifconfig_bridge0_name="igc0bridge"
# 将物理网卡(4个igcX)和虚拟网卡(tapX)连接到网桥上
ifconfig_igc0bridge="inet 192.168.7.201/24 addm igc0 addm igc1 addm igc2 addm igc3 addm tap0 addm tap1 addm tap2 up"
# 设置默认网关
defaultrouter="192.168.7.101"
# 激活物理网卡
ifconfig_igc0="up"
ifconfig_igc1="up"
ifconfig_igc2="up"
ifconfig_igc3="up"

警告

我的第一次实践因为是在 FreeBSD无线网络BCM43602(通过wifibox) 之后执行,当时已经有一个 wifibox 虚拟机,但是需要创建一个 tap1 设备( tap0 设备已经在之前由wifibox创建过了),并连接到 wifibox0 网桥(所以加了这段,你不需要):

定义 tap1 连接 wifibox0 网桥
# 创建tap设备,并连接到现有的wifibox0网桥上
ifconfig tap1 create
ifconfig wifibox0 addm tap1

设置启动时添加tap1:

启动时添加tap1
#bhyve的tap启动
cloned_interfaces="tap1"
ifconfig_wifibox0="addm tap1 up"

虚拟磁盘

可以使用文件作为虚拟磁盘(类似 qcow2 镜像文件),或者结合 ZFS 来构建数据集(更好)

创建虚拟磁盘文件

  • 创建虚拟机磁盘文件:

创建镜像文件
truncate -s 16G guest.img

创建ZFS数据集

对于host主机具备 ZFS 环境的话, 使用ZFS volumes来代替磁盘镜像,可以获得明显的性能提升

  • 创建 zroot/vms/debian :

创建vms数据集
zfs create -p zroot/vms
zfs set compression=lz4 zroot/vms

# 准备3个安装模版分别对应不同的虚拟机
zfs create -V16G -o volmode=dev zroot/vms/debian
zfs create -V16G -o volmode=dev zroot/vms/fedora
zfs create -V16G -o volmode=dev zroot/vms/freebsd

警告

如果同时在Host主机和虚拟机内部使用ZFS,需要避免两个系统缓存虚拟机内容时产生竞争内存压力。为了缓解这种情况,可以考虑将Host主机的ZFS设置为仅使用元数据缓存(指定虚拟机的特定 zvol 数据集)。以下命令案例是将 zroot/vms/freebsd 的zvol设置为仅缓存元数据(因为我准备在freebsd虚拟机中使用ZFS):

在Host主机上设置指定zvol仅缓存元数据
zfs set primarycache=metadata zroot/vms/freebsd

下载安装iso

  • 从debian官网下载安装镜像:

下载debian安装镜像
curl https://chuangtzu.ftp.acc.umu.se/debian-cd/current/amd64/iso-cd/debian-12.8.0-amd64-netinst.iso -o debian-12.8.0-amd64-netinst.iso
  • 下载Fedora安装镜像

下载fedora安装镜像
curl https://download.fedoraproject.org/pub/fedora/linux/releases/42/Server/x86_64/iso/Fedora-Server-netinst-x86_64-42-1.1.iso -o Fedora-Server-netinst-x86_64-42-1.1.iso
  • 下载FreeBSD安装镜像

下载freebsd安装镜像
curl https://download.freebsd.org/releases/amd64/amd64/ISO-IMAGES/14.2/FreeBSD-14.2-RELEASE-amd64-bootonly.iso -o FreeBSD-14.2-RELEASE-amd64-bootonly.iso

安装bhyve的Grub支持

通过 bhyveloadgrub-bhyve 的插件, bhyve hyperviosr可以使用UEFI firmware来启动虚拟机。这个选项可以用来支持那些特定的不支持其他loaders的guest操作系统。

grub 启动管理器是Linux guests启动建议的加载器,这样就能够运行 grub-bhyve 执行程序,也就是允许我们启动非FreeBSD guest操作系统:

安装grub相关软件包
pkg install grub2-bhyve bhyve-firmware

在安装了firmware之后,在 bhyve 命令行添加参数 -l bootrom,/path/to/firmware 来加载UEFI firmware

安装虚拟机

  • 执行以下命令开始启动虚拟机安装:

安装虚拟机
# debian
bhyve -c 1 -m 2G -w -H \
-s 0,hostbridge \
-s 3,ahci-cd,/home/admin/debian-12.8.0-amd64-netinst.iso \
-s 4,virtio-blk,/dev/zvol/zroot/vms/debian \
-s 5,virtio-net,tap0 \
-s 29,fbuf,tcp=0.0.0.0:5900,w=800,h=600,wait \
-s 30,xhci,tablet \
-s 31,lpc -l com1,stdio \
-l bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd \
debian

# fedora
# 使用完整镜像安装,我尝试netinst失败(安装交互过程中无法调整安装源) Fedora-Server-netinst-x86_64-42-1.1.iso
bhyve -c 1 -m 2G -w -H \
-s 0,hostbridge \
-s 3,ahci-cd,/home/admin/Fedora-Server-dvd-x86_64-42-1.1.iso \
-s 4,virtio-blk,/dev/zvol/zroot/vms/fedora \
-s 5,virtio-net,tap1 \
-s 29,fbuf,tcp=0.0.0.0:5901,w=800,h=600,wait \
-s 30,xhci,tablet \
-s 31,lpc -l com1,stdio \
-l bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd \
fedora

# freebsd
bhyve -c 1 -m 2G -w -H \
-s 0,hostbridge \
-s 3,ahci-cd,/home/admin/FreeBSD-14.2-RELEASE-amd64-bootonly.iso \
-s 4,virtio-blk,/dev/zvol/zroot/vms/freebsd \
-s 5,virtio-net,tap2 \
-s 29,fbuf,tcp=0.0.0.0:5902,w=800,h=600,wait \
-s 30,xhci,tablet \
-s 31,lpc -l com1,stdio \
-l bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd \
freebsd

命令参数:

  • -c 设置虚拟机vcpu数量

  • -H 输出给加载器的host文件系统

  • -l 使用OS loader(对于非FreeBSD需要使用uefi)

  • -m 设置虚拟机内存

  • -w 忽略没有实现的MSRs

  • -s 配置一个虚拟PCI slot 以及其他功能如硬盘,cdrom和其他设备

  • -A 生成ACPI表,对于FreeBSD/amd64 guests需要

  • -H 当检测到HLT指令是限制vcpu线程,如果该选项没有检测到,则vcpu可以使用100%的host CPU

  • -P 当检测到PAUSE指令时强制guest虚拟机vcpu退出

  • -s 29,fbuf,tcp=0.0.0.0:5900,w=800,h=600,wait 提供了 Graphical UEFI Framebuffer ,这对于图形安装界面非常有用,例如安装Windows就需要这个参数

异常

BdsDxe: failed to load Boot0002 "UEFI Misc Device"

VNC客户端连接

启动安装以后就可以使用 remmina 这样的VNC客户端俩皆 127.0.0.1:5900 来访问(如果是远程服务器,则使用服务器IP)

../../../_images/bhyve_debian.png

安装要点

安装结束前,最后一步需要返回并选择 Execute a shell 加载一个终端,然后需要将debian的efi文件复制出来给FreeBSD加载:

../../../_images/debian_installation_goback.png
../../../_images/debian_installation_shell.png
../../../_images/debian_installation_shell_1.png
在shell窗口执行 复制debian的efi
mkdir /target/boot/efi/EFI/BOOT/
# copy file - workaround for bhyve grub package #
# Pay attention to destination file bootx64.efi #
cp /target/boot/efi/EFI/debian/grubx64.efi /target/boot/efi/EFI/BOOT/bootx64.efi

备注

复制后的 efi 文件名是 bootx64.efi

启动

最后重启虚拟机,需要强制退出,然后再启动

  • 强制虚拟机关机:

停止虚拟机
bhyvectl --destroy --vm=debian
  • 启动虚拟机:

启动虚拟机
bhyve -c 2 -m 1G -w -H \
-s 0,hostbridge \
-s 4,virtio-blk,/dev/zvol/zroot/vms/debian \
-s 5,virtio-net,tap1 \
-s 29,fbuf,tcp=0.0.0.0:5900,w=1024,h=768,wait \
-s 30,xhci,tablet \
-s 31,lpc -l com1,stdio \
-l bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd \
debian
  • 简单的启动脚本:

启动虚拟机的简单脚本
#!/bin/sh
# Name: startdebianvm
# Purpose: Simple script to start my Debian 10 VM using bhyve on FreeBSD
# Author: Vivek Gite {https://www.cyberciti.biz} under GPL v2.x+
-------------------------------------------------------------------------
# Lazy failsafe (not needed but I will leave them here)
# 我简单修改适应我的环境
ifconfig tap1 create
ifconfig wifibox0 addm tap0
if ! kldstat | grep -w vmm.ko 
then
	kldload -v vmm
fi
if ! kldstat | grep -w nmdm.ko
then
	kldload -v nmdm
fi
bhyve -c 1 -m 1G -w -H \
-s 0,hostbridge \
-s 4,virtio-blk,/dev/zvol/zroot/vms/debian \
-s 5,virtio-net,tap1 \
-s 29,fbuf,tcp=0.0.0.0:5900,w=1024,h=768 \
-s 30,xhci,tablet \
-s 31,lpc -l com1,stdio \
-l bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd \
debian

注意,在终端执行虚拟机启动脚本,关闭终端会导致虚拟机退出,所以需要使用 tmux多会话终端管理 这样的终端管理器执行

可以设置在系统重启后执行的crontab:

@reboot /path/to/startdebianvm

参考