bhyve虚拟化运行Ubuntu

备注

在部署 xcloud 用于 cloud-atlas.dev 的后端基础运行环境,为后续 bhyve PCI Passthrough 准备,最终目标是实现 NVIDIA GPU 能够在FreeBSD的虚拟化环境中使用,构建 ollama 运行。

主机准备

内核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

  • /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"

虚拟磁盘

备注

我采用 ZFS 来构建本地存储

创建ZFS数据集

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

在构建 cloud-atlas.dev 模拟环境中,已经完成了 ZFS Stripe条带化 (FreeBSD环境实践) 部署,所以具备了 zdata 存储池,在此基础上完成虚拟机磁盘创建:

  • 创建 zdata/vms/ubuntu :

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

# 创建16G大小的 ZFS volume
# volmode=dev 表示这个ZFS volume(ZVOL)输出给操作系统时是作为 ``devfs`` 中的一个raw块设备(raw block device)
zfs create -V 16G -o volmode=dev zdata/vms/ubuntu

# 对于测试环境,为了节约磁盘可以使用稀疏卷(sparse volume),即创建卷时使用 -s 参数
# 这样raw disk不是马上分配,而是在数据写入时动态分配(可以分配远大于物理磁盘空间的虚拟磁盘,必要时再扩容底层zfs存储)
zfs create -sV 50G -o volmode=dev zdata/vms/ubuntu

备注

设置为 volmode=dev 的数据集不会自动挂载,所以在 /zdata/vms 目录下是空白的

下载安装iso

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

下载ubuntu安装镜像
curl https://mirrors.jxust.edu.cn/ubuntu-releases/24.04.2/ubuntu-24.04.2-live-server-amd64.iso -o ubuntu-24.04.2-live-server-amd64.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

安装虚拟机

BIOS模式启动bhyve虚拟机

警告

我这里尝试失败,手册中使用镜像文件,我模仿改成zfs卷集,没有启动成功。待后续再尝试

  • 创建一个设备映射文件以便grub能够将虚拟设备映射为host主机中的文件:

创建 /zdata/vms/ubuntu.map 配置文件作为设备映射
(hd0) /zdata/vms/ubuntu
(cd0) /zdata/docs/backup/software/ubuntu/ubuntu-24.04.2-live-server-amd64.iso
  • 使用 grub2-bhyve 从ISO镜像中加载Linux内核:

使用 grub2-bhyve 从ISO镜像中加载Linux内核
grub-bhyve -m ubuntu.map -r cd0 -M 4096M ubuntu

此时就会在终端进入Linux安装的grub界面(安装镜像包含了一个 grub.cfg )

进入安装界面
                               GNU GRUB  version 2.00

 +-------------------------------------------------------------------------------+
 |Try or Install Ubuntu Server                                                   |
 |Ubuntu Server with the HWE kernel                                              |
 |Test memory                                                                    |
 |                                                                               |
 |                                                                               |
 |                                                                               |
 |                                                                               |
 |                                                                               |
 |                                                                               |
 +-------------------------------------------------------------------------------+

      Use the ^ and v keys to select which entry is highlighted.
      Press enter to boot the selected OS, `e' to edit the commands before
      booting or `c' for a command-line.

使用UEFI Firmware启动bhyve虚拟机

bhyveloadgrub-bhyvebhyve hypervisor 提供了使用UEFI firmware启动虚拟机的功能。(需要安装 bhyve-firmware )

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

安装虚拟机
# ubuntu
bhyve -AHP -c 2 -m 4G -w \
-s 0,hostbridge \
-s 3,ahci-cd,/zdata/docs/backup/software/ubuntu/ubuntu-24.04.2-live-server-amd64.iso \
-s 4,virtio-blk,/dev/zvol/zdata/vms/ubuntu \
-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,/zdata/vms/ubuntu_BHYVE_UEFI_VARS.fd \
ubuntu

命令参数:

  • -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就需要这个参数

VNC客户端连接

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

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

启动

备注

我在 bhyve快速起步 实践中提到了按照handbook,在上述安装过程结束时候需要复制 grubx64.efibootx64.efi 。但是我现在实践没有执行这步efi文件复制,看起来也能够启动虚拟机。

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

  • 强制虚拟机关机:

停止虚拟机
bhyvectl --destroy --vm=ubuntu
  • 启动虚拟机(去除了cdrom配置):

启动虚拟机 start_ubuntu
# ubuntu 去除掉iso启动参数就能够直接启动
bhyve -AHP -c 2 -m 4G -w \
-s 0,hostbridge \
-s 4,virtio-blk,/dev/zvol/zdata/vms/ubuntu \
-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,/zdata/vms/ubuntu_BHYVE_UEFI_VARS.fd \
ubuntu

生成虚拟机配置

上述启动虚拟机需要很长的命令行,为了方便启动,可以先把虚拟机配置dump出来,也就是修改上述 start_ubuntu ,添加一行 -o config.dump=1 参数,就可以输出配置(需要重定向到文件):

启动虚拟机 start_ubuntu 重定向输出vm配置
# ubuntu 去除掉iso启动参数就能够直接启动
bhyve -AHP -c 2 -m 4G -w \
-s 0,hostbridge \
-s 4,virtio-blk,/dev/zvol/zdata/vms/ubuntu \
-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,/zdata/vms/ubuntu_BHYVE_UEFI_VARS.fd \
-o config.dump=1 \
ubuntu > ubuntu.config

此时生成的配置文件 ubuntu.config 如下:

启动虚拟机 start_ubuntu 重定向输出vm配置文件 ubuntu.config
acpi_tables_in_memory=true
memory.size=4G
x86.vmexit_on_hlt=true
x86.vmexit_on_pause=true
x86.strictmsr=false
lpc.fwcfg=bhyve
lpc.com1.path=stdio
lpc.bootrom=/usr/local/share/uefi-firmware/BHYVE_UEFI.fd
lpc.bootvars=/zdata/vms/ubuntu_BHYVE_UEFI_VARS.fd
acpi_tables=true
cpus=2
pci.0.0.0.device=hostbridge
pci.0.4.0.device=virtio-blk
pci.0.4.0.path=/dev/zvol/zdata/vms/ubuntu
pci.0.5.0.device=virtio-net
pci.0.5.0.backend=tap0
pci.0.29.0.device=fbuf
pci.0.29.0.tcp=0.0.0.0:5900
pci.0.29.0.w=800
pci.0.29.0.h=600
pci.0.29.0.wait=true
pci.0.30.0.device=xhci
pci.0.30.0.slot.1.device=tablet
pci.0.31.0.device=lpc
config.dump=1
name=ubuntu
  • 删除掉上述配置文件中 config.dump=1 行,就可以使用 -k 参数来启动虚拟机:

使用 -k 指定配置文件启动虚拟机
bhyve -k ubuntu.config

参考