找资料
bhyve是FreeBSD特有的虚拟机技术,FreeBSD本身就很少有人玩,bhyve资料就更少了,尤其是中文的。
首先学习FreeBSD handbook 中的 22.6 FreeBSD as a Host with bhyve。
以后找到其他学习资料再更新。
22.6.bhyve简介
bhyve从FreeBSD10.0版以后称为基础系统的一部分。
默认情况下,bhyve提供对串行控制台的访问,而不模拟图形控制台。
Intel处理器需要支持扩展页表(Extended Page Tables,EPT)
AMD处理器需要支持快速虚拟化索引(Rapid Virtualization Indexing,RVI)或嵌套页表(Nested Page Tables,NPT)。
使用多个vCPU托管的Linux来宾或FreeBSD来宾需要VMX无限制模式支持(uG),大多数新的Intel处理器都支持此功能
RVI是在第三代和更高版本AMD Opteron上引入的
判断CPU是否支持bhyve的最简单方法是运行dmesg或查看/var/run/dmesg文件,AMD处理器的Features2行上的POPCNT处理器功能标志,对于Intel处理器,VT-x行中有EPT和UG标志。
22.6.1.准备主机
第一步是配置主机系统,首先使用以下命令加载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
使用ifconfig可以看到新建的两个设备(实作平台的物理网卡是re0):
tap0: flags=8902 metric 0 mtu 1500
options=80000
ether 58:9c:fc:10:ff:cf
groups: tap
media: Ethernet autoselect
status: no carrier
nd6 options=29
bridge0: flags=8843 metric 0 mtu 1500
ether 58:9c:fc:10:ff:90
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: tap0 flags=143
ifmaxaddr 0 port 7 priority 128 path cost 2000000
member: re0 flags=143
ifmaxaddr 0 port 1 priority 128 path cost 20000
groups: bridge
nd6 options=9
22.6.2.创建一个FreeBSD来宾
创建一个文件,用作来宾计算机的虚拟磁盘。指定虚拟磁盘的大小和名称:
# truncate -s 16g guest.img
下载安装镜像(实作使用的连接为 https://mirrors.ustc.edu.cn/freebsd/releases/ISO-IMAGES/12.2/FreeBSD-12.2-RELEASE-amd64-bootonly.iso):
# 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(字母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
实作使用bootonly镜像安装过程中需要下载安装包,配置好网卡(网桥是直通的,所以可以按照局域网中实体机的样式为网卡设置IP、子网掩码、网关等)之后在选择站点时建议选other,然后输入将URL中releases前面的改成“https://mirrors.ustc.edu.cn/freebsd/”,否则从官方主站几乎无法下载。
安装完成后如果重启还会进入安装模式,因为前面vmrun命令行中用的-i模式,会从光盘启动。所以在安装过程的最后一步,询问是否进入shell时,应选是,然后使用shutdown命令关机。
现在,用以下命令可以从虚拟磁盘启动来宾:
# sh /usr/share/examples/bhyve/vmrun.sh -c 4 -m 1024m -t tap0 -d guest.img guestname
注:每个来宾需要分配一个虚拟网卡。若要同时运行两个来宾,需要为其他来宾创建新的虚拟网卡并绑定到虚拟网桥上:
# ifconfig tap1 create
# ifconfig bridge0 addm tap1
此时新加虚拟网卡不需要重启网络。
22.6.3.创建一个linux来宾
要启动FreeBSD以外的操作系统,需要先安装sysutils/grub2-bhyve。
下一步,为来宾机器创建一个文件作为虚拟盘:
# truncate -s 16g linux.img
使用bhyve启动虚拟机需要两个步骤:首先加载内核,然后才能启动来宾。
使用sysutils/grub2-bhyve加载linux内核。
创建一个device.map文件,grub将用此文件将虚拟机设备映射到主机系统。此文件将包含类似以下内容:
(hd0) ./linux.img
(cd0) ./somelinux.iso
然后使用sysutils/gurb2-bhyve从ISO镜像加载linux内核:
# grub-bhyve -m device.map -r cd0 -M 1024m linuxguest
以上命令将启动grub。如果安装CD包含grub.cfg,会显示要给菜单。如果不包含,必须手动找到并加载vmlinuz和initrd文件。
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,tap1 \
-s 3:0,virtio-blk,./linux.img -l com1,stdio -c 4 -m 1024M linuxguest
在虚拟机中完成操作后,重启虚拟机以退出bhyve。然后销毁虚拟机实例:
# bhyvectl --destroy --vm=linuxguest
实作中,执行grub-bhyve命令中的ls命令时只看到(host),无法启动。暂时放弃。
22.6.4.使用UEFI固件启动bhyve虚拟机
除了bhyveload和grub-bhyve,bhyve虚拟机监控程序(hypervisor)还可以使用UEFI用户空间固件。此选项可以是bhyve支持其他来宾操作系统。
为了利用bhyve中的UEFI支持,首先要获取UEFI固件映像。这可以通过安装sysutils/bhyve-firmware来实现。
固件就位后,将标志-l bootrom,/path/to/firmware添加到命令行。实际的bhyve命令可能如下所示:
# 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-firmware还包含一个CSM-enabled的固件,允许不支持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
实作时使用以上方法启动win10安装程序未成功,可能需要按下一节介绍的操作。
22.6.5.用于bhyve来宾的图形UEFI帧缓冲区(Framebuffer)
UEFI固件支持对于以图形为主的来宾操作系统(如Microsoft Windows®)尤其有用。
对UEFI-GOP帧缓冲区的支持也可以通过-s 29,fbuf,tcp=0.0.0.0:5900标志启用。
帧缓冲区分辨率可以配置为w=800和h=600,并且可以通过添加wait选项来命令bhyve在引导来宾之前等待VNC连接。
帧缓冲区可以从主机访问,也可以通过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仿真模式下,一旦控制从固件传递到来宾操作系统,帧缓冲区将停止接收更新。
使用此方法可以启动win10安装程序,但是提示找不到硬盘,可能需要线格式化zfs卷。待后续实验。
2022/1/12
网上找资料发现,硬盘项应该是:-s 3:0,ahci,/dev/zvol/zbhyve/win10,而不是virtio-blk。
实作的命令为:
# bhyve -AHP -s 0:0,hostbridge -s 31:0,lpc -s 2:0,virtio-net,tap0 -s 3:0,ahci,/dev/zvol/zbhyve/win10 \
-s 4:0,achi-cd,/zbhyve/iso/win10.iso -c 2 -m 2048m -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 win10guest
运行此命令后要尽快使用vnc客户端软件连接它,否则启动光盘超时后会尝试从硬盘启动。
实作后进入系统发现无法驱动网卡。
2022/1/13
从网上下载了virtio-win ISO镜像文件,放到/zbhyve/iso/目录中。
上面实作命令完成安装后更换成:
# bhyve -AHP -s 0:0,hostbridge -s 31:0,lpc -s 2:0,virtio-net,tap0 -s 3:0,ahci,/dev/zvol/zbhyve/win10 \
-s 4:0,achi-cd,/zbhyve/iso/virtio-win.iso -c 2 -m 2048m -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 win10guest
进入来宾win10,在设备管理器中安装网卡驱动成功,显示的是Red Hat VirtIO Ethernet Adapter,自动获取到来自DHCP的IP地址。
但以上命令尝试修改-m参数时收到提示:Unable to setup memory(22),难道不能修改内存?-c是可以修改的。
22.6.6.与bhyve来宾一起使用ZFS
如果ZFS在主机上可用,则使用ZFS卷而不是磁盘映像文件可以为来宾VM提供显著的性能优势。
ZFS卷可以通过以下方式创建:
# zfs create -V16g -o volmode=dev zroot/linuxdisk0
启动VM时,指定ZFS卷替代磁盘驱动器:
# bhyve -AHP -s 0:0,hostbridge -s 1:0,lpc -s 2:0,virtio-net,tap0 -s 3:0,virtio-blk,/dev/zvol/zroot/linuxdisk0 \
-l com1,stdio -c 4 -m 1024M linuxguest
大概可以理解为,不需要使用前面的truncate -s 16g linux.img命令创建虚拟磁盘。而在安装和启动时,将命令中-s 3:0,virtio-blk,./linux.img替换成-s 3:0,virtio-blk,/dev/zvol/zroot/linuxdisk0。
但是手册中未提到freebsd来宾的示例。实测时,如果创建ZFS卷的命令行中有-o volmode=dev则在/dev中无zvol目录;若无-o volmode=dev,则会在/dev中创建对应的文件。
若创建freebsd来宾时使用ZFS卷,则命令应改为以下形式:
# zfs create -V 16g zbhyve/freebsd1
# sh /usr/share/examples/bhyve/vmrun.sh -c 1 -m 1024m -t tap0 -d /dev/zvol/zbhyve/freebsd1 -i -I FreeBSD-12.2-RELEASE-amd64-bootonly.iso guestname
前面已经创建了一个FreeBSD虚拟机,先在虚拟机中使用shutdown停掉它,然后运行
# dd if=/zbhyve/guest/guest.img of=/dev/zvol/zbhyve/freebsd1 bs=1M conv=sync
将虚拟磁盘复制到zfs卷。
然后运行以下命令启动虚拟机:
# sh /usr/share/examples/bhyve/vmrun.sh -c 2 -m 2048m -t tap0 -d /dev/zvol/zbhyve/freebsd1 guestname
实际启动中发现,以前使用磁盘镜像时会在Launching APs:1 2 3处停顿数分钟,改成ZFS卷后不会卡了。
22.6.7.虚拟机控制台
为便利,应将bhyve控制台封装在会话管理工具(如sysutils/tmux或sysutils/screen)中,以便分离并重新连接到控制台。
也可以将bhyve的控制台设置为可通过cu访问的空的调制解调器设备。
为此,可加载nmdm内核模块并将-l com1,stdio替换为-l com1,/dev/nmdm0A
根据需要自动创建/dev/nmdm设备,其中每个设备都是一对,对应于空的调制解调器电缆(/dev/nmd0A和/dev/nmdm0B)的两端。
# 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来宾,必须在指定文件中进行以下配置:
- /etc/sysctl.conf
net.link.tap.up_on_open=1
- /etc/rc.conf
cloned_interfaces="bridge0 tap0"
ifconfig_bridge0="addm igb0 addm tap0"
kld_list="nmdm vmm"
但以上所谓持久配置,只为虚拟机创建了一个虚拟网卡,若创建多个虚拟机,不知如何自动将新的虚拟网卡添加到/etc/rc.conf中。