vm-bhyve

我在直接使用 bhyve 命令时遇到的问题是无法修订创建的虚拟机配置: 在 bhyve虚拟化运行Ubuntu 以及 bhyve PCI Passthrough快速起步 时尝试修订 -m 参数指定不同的内存大小都会报错。

Github: freebsd/vm-bhyve 是一个基于 Shell 的最小化依赖的 bhyve manager ,非常方便管理虚拟机

安装

  • 安装 vm-bhyve

安装 vm-bhyve
pkg install vm-bhyve bhyve-firmware

可以看到会依赖安装3个软件包:

安装 vm-bhyve 会安装3个软件包
New packages to be INSTALLED:
        bhyve-firmware: 1.0_2 [FreeBSD]
        edk2-bhyve: g202308_5 [FreeBSD]
        vm-bhyve: 1.6.2 [FreeBSD]
  • 创建存储:

    • 创建 zdata/vms ZFS 存储数据集,并且将默认 recordsize 属性 128K 调整为 64K

    • 创建 zdata/vms/.templates 存储用于创建VM的模版

创建虚拟机存储数据集
zfs create zdata/vms

#zfs set recordsize=64K zdata/vms

zfs create zdata/vms/.config
zfs create zdata/vms/.img
zfs create zdata/vms/.iso
zfs create zdata/vms/.templates
  • /etc/rc.conf 中设置虚拟化支持:

配置 /etc/rc.conf 支持虚拟化
# needed for virtualization support
vm_enable="YES"
vm_dir="zfs:zdata/vms"
  • /boot/loader.conf 添加:

/boot/loader.conf
# needed for virtualization support 
vmm_load="YES"
  • 初始化:

初始化
vm init

初始化步骤会激活 /etc/rc.confvm-bhyve 并设置使用的数据集,可以看到 /zroot/bhyve 目录下创建了:

vm init 创建了zfs数据集目录
root@xcloud:/zroot/bhyve # ls -lh
total 2
drwxr-xr-x  2 root wheel    4B Jul 22 23:56 .config
drwxr-xr-x  2 root wheel    2B Jul 22 23:56 .img
drwxr-xr-x  2 root wheel    2B Jul 22 23:56 .iso
drwxr-xr-x  2 root wheel    3B Jul 22 23:56 .templates

备注

我在构建 zdata/vms zfs存储数据集时候,为每个 .xxx 目录构建了一个子存储卷。这个步骤不是必须的,我考虑是今后可以做隔离和quota。

在完成初始化之后,检查 /zdata/vms 下面的上述4个子目录,可以看到 .config 目录下有2个空文件:

.config 目录下有2个空文件
-rw-r--r--  1 root wheel    0B Jul 24 16:42 null.iso
-rw-r--r--  1 root wheel    0B Jul 24 16:42 system.conf

而在 .templates 目录下则有一个 default.conf 内容如下:

.templates 目录下 default.conf
loader="bhyveload"
cpu=1
memory=256M
network0_type="virtio-net"
network0_switch="public"
disk0_type="virtio-blk"
disk0_name="disk0.img"
  • /usr/local/share/examples/vm-bhyve/ 目录下有虚拟机的配置模版案例,所谓的配置模版其实是一些简单的配置项来指定虚拟机如何运行。对于 vm-bhyve 使用的模版是存放在 $vm_dir/.templates ,所以执行以下命令复制模版:

复制模版
cp /usr/local/share/examples/vm-bhyve/* /zdata/vms/.templates/

备注

复制模版文件中有一个 config.sample 包含了详细的配置解析,可以参考这个配置案例来修订自己的配置文件

使用

参考 config.sample ,我尝试定制自己的模版文件来实现 bhyve 虚拟机构建:

虚拟交换机

  • 默认情况下可以创建一个 public 虚拟机交换机,然后将物理主机的某个网卡加入(例如 em0 ),这样后续配置虚拟机的时候,只要为虚拟机指定这个 public 虚拟机交换机,那么虚拟机的虚拟网卡就会连接上 public 虚拟交换机,并通过 em0 网卡连接外部物理真实网络:

创建虚拟交换机并连接物理网卡
vm switch create public
vm switch add public em0

不过,我的实践有所不同: 我已经在 FreeBSD bridge快速起步bhyve快速起步 实践时构建了一个共用的虚拟交换机 igc0bridge ,也就是在 /etc/rc.conf 中配置了:

/etc/rc.conf 中配置虚拟交换机 igc0bridge
# 创建网桥以及用于虚拟机的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"

所以在 vm-bhyve 中复用这个虚拟交换机: vm-hbyve 在模版文件中设置 network0_switch="igc0bridge" 来指定

存储

  • vm create 命令时可以通过 -d <datastore> 指定和默认 vm_dir 不一样的ZFS存储数据集,例如我的 /etc/rc.conf 配置了 vm_dir="zfs:zdata/vms" ,但是我如果想要在另外一个 zstore/bhyve 数据集中创建一个虚拟机,则可以使用( ⚠️ 我还没有验证):

    vm create -d zstore/bhyve ...
    
  • bhyve虚拟化运行Ubuntu 实践中,我使用了 ZFS volume 来作为虚拟机的磁盘,这种 raw disk 可以提高存储性能。不过实验环境也可以使用 zfs create -sV 50G -o volmode=dev ... 来构建稀疏卷(sparse volume)来节约存储空间占用

警告

⚠️

不需要预先为 vm-bhyve 手工创建 稀疏卷(sparse volume) ,因为其内置了创建功能,而且约定了:

DEVICE TYPE        DISK NAME      BHYVE PATH USED
zvol|sparse-zvol  'disk0'     -> '/dev/zvol/pool/dataset/path/guest/disk0'

也就是说,只要配置了:

disk0_dev="sparse-zvol"
disk0_name="disk0"

就会自动在 /zdata/vms/mdev 目录下创建一个 disk0 稀疏卷(这里 zdata/vms 是指定的虚拟机卷集, mdev 是虚拟机名

bhyve PCI Passthrough

vm-bhyve 支持 bhyve PCI Passthrough ,并且可以检查系统中哪些设备可以passthrough:

检查可以passthrough的设备
 vm passthru

我的 Nvidia Tesla P10 GPU运算卡 已经在 :ref:`` 配置好passthrough,所以输出现实状态已经就绪:

检查可以passthrough的设备: 可以看到Tesla P10
DEVICE     BHYVE ID     READY        DESCRIPTION
hostb0     0/0/0        No           8th Gen Core 4-core Workstation Processor Host Bridge/DRAM Registers [Coffee Lake
 S]
pcib1      0/1/0        No           6th-10th Gen Core Processor PCIe Controller (x16)
pcib2      0/1/1        No           Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor PCIe Controller (x8)
pcib3      0/1/2        No           Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor PCIe Controller (x4)
vgapci0    0/2/0        No           CoffeeLake-S GT2 [UHD Graphics P630]
...
ppt0       1/0/0        Yes          GP102GL [Tesla P10]
nvme0      2/0/0        No           NVMe SSD
nvme1      3/0/0        No           NVMe SSD
nvme2      5/0/0        No           NVMe SSD
igc0       6/0/0        No           Ethernet Controller I226-V
igc1       7/0/0        No           Ethernet Controller I226-V
igc2       8/0/0        No           Ethernet Controller I226-V
igc3       9/0/0        No           Ethernet Controller I226-V
nvme3      10/0/0       No           NVMe SSD

此时配置文件就可以设置:

配置passthrough设备
passthru0="1/0/0=2:0"

备注

vm-bhyve 参考手册中, vm passthru 没有任何参数,只能显示当前可以passthrough的设备列表。似乎只有配置文件能够指定传递的设备

启动设备

vm-bhyve 配置中使用了一个 start_slot 参数和 install_slot 参数:

  • 对于UEFI虚拟机,一些UEFI虚拟机要求磁盘slot是 3-6vm-bhyve 默认使用 4 作为磁盘slot,而 3 保留给安装ISO

VNC图形界面

vm-bhyve 提供了一个 graphics 参数来支持VNC,端口从5900开始找寻,通过 vm list|info 输出可以看到虚拟机的VNC端口:

# 默认提供VNC
graphics="yes"

配置

  • /zdata/vms/.templates 构建一个我的自定义模版 x-vm.conf :

自定义模版 x-vm.conf
loader="uefi"
cpu=4
memory=16G
wired_memory="yes"
network0_type="virtio-net"
network0_switch="igc0bridge"
network0_device="tap0"
disk0_name="disk0"
disk0_dev="sparse-zvol"
disk0_type="virtio-blk"
disk0_size="50G"
#passthru0="1/0/0=2:0"
graphics="yes"
graphics_listen="0.0.0.0"
graphics_port="5900"
  • 配置说明:

    • wired_memory 是因为 bhyve PCI Passthrough 需要

    • disk0_dev 指定为 sparse-zvol ,这样 vm-bhyve 会自动创建 /zdata/vms/mdev 作为虚拟机存储数据集,并在下面创建一个 sparse volume raw磁盘 disk0

    • network0_switch 指定了我预先配置的 igc0bridge 虚拟交换机

    • network0_device 这里设置了 tap0 而不是让 vm-bhyve 自动生成,是因为我发现我配置了指定交换机之后,自动生成的 tap3 没有 addm 到我指定的 igc0bridge 虚拟交换机,导致网络不通。我参考 config.sample 特定指定了我之前配置好的 tap0 (已经连接在 igc0bridge 上)就解决了这个网络问题

    • 我发现初次安装的时候不能直接把 Nvidia Tesla P10 GPU运算卡 直接 passthru 进虚拟机,会导致虚拟机启动后VNC没有输出(估计虚拟机发现有NVIDIA Nvidia Tesla P10 GPU运算卡 导致默认输出到GPU上了。这里注销掉GPU就能安装,后续安装完再修订配置加入 pcie passthru

  • 创建虚拟机:

创建虚拟机 mdev
vm create -t x-vm -s 60G mdev

-t x-vm 表示使用 /zdata/vms/.templates 目录下的 x-vm.conf 作为模版,我这里使用了 -s 60G 创建了一个特定的60G虚拟磁盘,配置中默认我设置了 50G

  • 在上述创建了虚拟机之后,就可以看到ZFS构建了一个 zdata/vms/mdev 存储集,并且在这个存储集下有一个 disk0zvol raw disk:

创建的虚拟机 mdev 对应的ZFS
root@xcloud:~ # df -h
Filesystem                                     Size    Used   Avail Capacity  Mounted on
...
zdata/vms/mdev                                 4.4T    116K    4.4T     0%    /zdata/vms/mdev

root@xcloud:~ # zfs list | grep vms
zdata/vms                                      784K  4.39T   120K  /zdata/vms
...
zdata/vms/mdev                                 172K  4.39T   116K  /zdata/vms/mdev
zdata/vms/mdev/disk0                            56K  4.39T    56K  -
  • vm-bhyve 提供了一个 vm iso 命令用于将镜像下载到 .iso 目录下(对于我的环境是 /zdata/vms/.iso ),也可以手工将已经下载的镜像iso文件移动到该目录(我在该目录下保存了我下载的 ubuntu-24.04.2-live-server-amd64.iso )

  • 安装ubuntu:

安装虚拟机
vm install mdev ubuntu-24.04.2-live-server-amd64.iso

终端输出显示:

安装虚拟机终端显示
Starting mdev
  * found guest in /zdata/vms/mdev
  * booting...

虚拟机配置修改

我需要实现 bhyve PCI Passthrough ,所以修订虚拟机配置 /zdata/vms/mdev/mdev.conf (这个配置是 vm create 时创建的):

修订 /zdata/vms/mdev/mdev.conf
loader="uefi"
cpu=4
memory=16G
wired_memory="yes"
network0_type="virtio-net"
network0_switch="igc0bridge"
network0_device="tap0"
disk0_name="disk0"
disk0_dev="sparse-zvol"
disk0_type="virtio-blk"
passthru0="1/0/0=2:0"
graphics="yes"
graphics_listen="0.0.0.0"
graphics_port="5900"

uuid="ece97590-689f-11f0-a949-0003ee002989"
network0_mac="58:9c:fc:09:6b:0a"

奇怪,启动虚拟机VNC控制台没有任何输出

我检查了 /zdata/vms/mdev/vm-bhyve.log :

vm-bhyve.log 日志没有看出报错
Jul 24 23:47:31: initialising
Jul 24 23:47:31:  [loader: uefi]
Jul 24 23:47:31:  [cpu: 4]
Jul 24 23:47:31:  [memory: 16G]
Jul 24 23:47:31:  [hostbridge: standard]
Jul 24 23:47:31:  [com ports: com1]
Jul 24 23:47:31:  [uuid: ece97590-689f-11f0-a949-0003ee002989]
Jul 24 23:47:31:  [debug mode: no]
Jul 24 23:47:31:  [primary disk: disk0]
Jul 24 23:47:31:  [primary disk dev: sparse-zvol]
Jul 24 23:47:31: initialising network device tap0
Jul 24 23:47:31: failed to find virtual switch 'igc0bridge'
Jul 24 23:47:31: booting
Jul 24 23:47:31:  [bhyve options: -c 4 -m 16G -AHPw -l bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd -S -U ece97590-689f-11f0-a949-0003ee002989 -u -S]
Jul 24 23:47:31:  [bhyve devices: -s 0,hostbridge -s 31,lpc -s 4:0,virtio-blk,/dev/zvol/zdata/vms/mdev/disk0 -s 5:0,virtio-net,tap0,mac=58:9c:fc:09:6b:0a -s 2:0,passthru,1/0/0 -s 7:0,fbuf,tcp=0.0.0.0:5900]
Jul 24 23:47:31:  [bhyve console: -l com1,/dev/nmdm-mdev.1A]
Jul 24 23:47:31: starting bhyve (run 1)

我加上了debug模式,但是输出的日志没有变化

另外 Experience from bhyve (FreeBSD 14.1) GPU passthrough with Windows 10 guest 提到了将slot修改为8,我也尝试了不行:

#passthru0="1/0/0=8:0"
passthru0="1/0/0"

如果不指定slot参数,会自动找一个可用的,我发现是 6:0 :

最简化 passthru0="1/0/0"
Jul 25 00:15:05:  [bhyve options: -c 4 -m 16G -AHPw -l bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd -S -U ece97590-689f-11f0-a949-0003ee002989 -u -S]
Jul 25 00:15:05:  [bhyve devices: -s 0,hostbridge -s 31,lpc -s 4:0,virtio-blk,/dev/zvol/zdata/vms/mdev/disk0 -s 5:0,virtio-net,tap0,mac=58:9c:fc:09:6b:0a -s 6:0,passthru,1/0/0 -s 7:0,fbuf,tcp=0.0.0.0:5900]
Jul 25 00:15:05:  [bhyve console: -l com1,/dev/nmdm-mdev.1A]
Jul 25 00:15:05: starting bhyve (run 1)

但是还是VNC没有任何输出黑屏。这个问题我一直没有解决,我尝试 在bhyve中实现NVIDIA GPU passthrough 来解决 Nvidia Tesla P10 GPU运算卡 passthru没有成功,但是发现同样的配置 Nvidia Tesla P4 GPU运算卡 是正常工作的。此问题待排查

虚拟机重命名

vm-bhyve 提供了 rename 指令可以重命名虚拟机,并且对于 ZFS 存储,可以非常丝滑地转换zfs存储集地名字以及对应地配置,所以不需要人工干预处理,非常实用:

重命名虚拟机
vm-bhyve rename mdev xdev

参考