Top

找资料

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中运行虚拟机的示例脚本,该脚本将启动虚拟机并在循环中运行,因此,如果虚拟机崩溃,它将自动重新启动。
    该脚本采用许多选项来控制及其的配置: 最后一个参数是虚拟机的名称,用于跟踪正在运行的机器。
    以下示例以安装模式启动虚拟机:
    # 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,会显示要给菜单。如果不包含,必须手动找到并加载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,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=800h=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/rc.conf中。