KVM
KVM 是一个内核模块中的自由开源虚拟化解决方案。虽然它通常简称为 KVM,但实际的 hypervisor 是 QEMU。QEMU 从用户空间运行,但可以与 KVM 集成,通过利用内核空间的硬件来提供更好的性能。QEMU 可以虚拟化 x86、PowerPC 和 S390 客户机等。Libvirt 是一个管理框架,它与 QEMU/KVM、LXC、Xen 等集成。
安装
以下命令提供 libvirt 以及 用于 x86_64 仿真的 QEMU 和 qemu-img,qemu-img 是使用各种磁盘格式(如 qcow2)的必要组件。如果没有 qemu-img,则只能使用原始磁盘。它还可以在 vhdx 和 vmdk 等多种格式之间转换镜像。它还提供了元软件包 qemu-modules,该软件包提供了特殊功能所需的子软件包。在 Alpine 3.13.0 之前的版本中,这些功能由 用于 x86_64 仿真的 QEMU 涵盖。
# apk add libvirt-daemon qemu-img qemu-system-x86_64 qemu-modules openrc # rc-update add libvirtd
网络配置
默认情况下,libvirt 使用 NAT 进行虚拟机连接。如果要使用默认配置,则需要加载 tun 模块。
# modprobe tun
将 tun 添加到自动启动
# echo "tun" >> /etc/modules-load.d/tun.conf
要使 tun 模块在启动时加载,请使用此命令
# cat /etc/modules | grep tun || echo tun >> /etc/modules
如果希望通过以太网接口桥接客户机,则需要创建一个桥接。
在 KVM 环境中使用桥接非常常见。但是当使用 IPv6 时,Alpine 会为自己分配一个链路本地地址以及一个 SLAAC 地址,以防路由器发送路由器通告。您不希望这样做,因为您不希望 KVM 主机在它为客户机服务的每个网络中都拥有 IP 地址。不幸的是,IPv6 不能仅仅通过 sysctl 配置文件为桥接禁用,因为桥接可能在启动期间应用 sysctl 配置时尚未启动。有效的方法是在 /etc/network/interfaces 文件中放入一个 post-up hook,如下所示
auto brlan iface brlan inet manual bridge-ports eth1.5 bridge-stp 0 post-up ip -6 a flush dev brlan; sysctl -w net.ipv6.conf.brlan.disable_ipv6=1
管理
对于非 root 用户管理,您需要将您的用户添加到 libvirt 组。
# addgroup user libvirt
您可以使用 libvirt 的 virsh 在 CLI 中进行管理。它可以执行命令以及作为交互式 shell 运行。阅读其手册页和/或使用“help”命令获取更多信息。一些基本命令是
virsh help virsh list --all virsh start $domain virsh shutdown $domain
libvirt 项目提供了一个用于管理主机的 GUI,称为 virt-manager。它处理本地系统以及通过 SSH 的远程系统。
# apk add dbus polkit virt-manager font-terminus # rc-update add dbus
为了使用 libvirtd 通过 ssh 远程控制 KVM,PolicyKit 需要一个 .pkla 文件来告知它这是允许的。将以下文件写入 /etc/polkit-1/localauthority/50-local.d/50-libvirt-ssh-remote-access-policy.pkla
[远程 libvirt SSH 访问] Identity=unix-group:libvirt Action=org.libvirt.unix.manage ResultAny=yes ResultInactive=yes ResultActive=yes
使用 virt-install 供应 Alpine Linux 虚拟机
您可以使用 virt-install 在 VM 中安装 Alpine。首先创建 meta-data 和 user-data 文件。meta-data
hostname: alpine-vm
user-data:
#alpine-config ssh_authorized_keys: - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOIiHcbg/7ytfLFHUNLRgEAubFz/13SwXBOM/05GNZe4 ncopa@ncopa-desktop apk: repositories: - base_url: https://dl-cdn.alpinelinux.org/alpine repos: - main - community packages: - tmux - curl runcmd: - rm /etc/runlevels/*/tiny-cloud* - lbu include /root/.ssh /home/alpine/.ssh - ERASE_DISKS=/dev/vda setup-disk -m sys /dev/vda - poweroff
然后运行
virt-install --name alpine-vm \ --disk size=4 \ --location $HOME/Downloads/alpine-virt-3.20.1-x86_64.iso,kernel=boot/vmlinuz-virt,initrd=boot/initramfs-virt \ --extra-args console=ttyS0 \ --osinfo alpinelinux3.19 \ --graphics none \ --console pty,target_type=serial \ --cloud-init meta-data=meta-data,user-data=user-data
虚拟机生命周期管理
libvirt-guests 服务(从 Alpine 3.13.5 开始可用)允许在主机关闭或重启时自动挂起或关闭正在运行的虚拟机。
该服务在 /etc/conf.d/libvirt-guests 中配置。使用以下命令启用该服务
# rc-update add libvirt-guests
vfio
VFIO 是一种更灵活的 PCI 直通方式。假设您想在 VM 中使用以下以太网卡作为 PCI 设备。
# lspci | grep 02:00.0 02:00.0 Ethernet controller: Intel Corporation 82576 Gigabit Network Connection (rev 01) # lspci -n -s 02:00.0 02:00.0 0200: 8086:10c9 (rev 01)
首先,创建 /etc/mkinitfs/features.d/vfio.modules,内容如下,以便 mkinitfs 将 VFIO 模块包含在 initramfs 中。
kernel/drivers/vfio/vfio.ko.* kernel/drivers/vfio/vfio_virqfd.ko.* kernel/drivers/vfio/vfio_iommu_type1.ko.* kernel/drivers/vfio/pci/vfio-pci.ko.*
将 vfio 添加到 /etc/mkinitfs/mkinitfs.conf 中的功能列表中。
修改以下文件以指示 mkinitfs 加载以下带有选项的模块并重建内核 ramdisk。
# cat /etc/modprobe.d/vfio.conf <<EOF options vfio-pci ids=8086:10c9 options vfio_iommu_type1 allow_unsafe_interrupts=1 softdep igb pre: vfio-pci EOF # mkinitfs
现在我们需要编辑 update-extlinux.conf 文件中的“default_kernel_opts”和“modules”部分。编辑“default_kernel_opts”以包含 Intel 平台的 intel_iommu=o iommu=pt(AMD 使用 amd_iommu=on),并将 VFIO 模块添加到“modules”部分。
# grep '^default_kernel_opts\|^modules' /etc/update-extlinux.conf default_kernel_opts="quiet rootfstype=ext4 intel_iommu=on iommu=pt" modules=sd-mod,usb-storage,ext4,raid1,vfio,vfio-pci,vfio_iommu_type1,vfio_virqfd
对于 syslinux/extlinux,运行
# update-extlinux
对于 GRUB(如果存在 update-extlinux.conf,现在也使用),运行
# grub-mkconfig -o /boot/grub/grub.cfg
重启并检查 dmesg。
# grep -i -e DMAR -e IOMMU /var/log/dmesg [ 0.343795] DMAR: Host address width 36 [ 0.343797] DMAR: DRHD base: 0x000000fed90000 flags: 0x1 [ 0.343804] DMAR: dmar0: reg_base_addr fed90000 ver 1:0 cap c90780106f0462 ecap f020e3 [ 0.343806] DMAR: RMRR base: 0x000000000ed000 end: 0x000000000effff [ 0.343807] DMAR: RMRR base: 0x000000bf7ed000 end: 0x000000bf7fffff [ 0.553830] iommu: Default domain type: Passthrough (set via kernel command line) [ 0.902477] DMAR: No ATSR found [ 0.902563] DMAR: dmar0: Using Queued invalidation ... [ 0.903256] pci 0000:02:00.0: Adding to iommu group 12 ... [ 0.903768] DMAR: Intel(R) Virtualization Technology for Directed I/O
如果您不在 root 下运行 libvirt 虚拟机 (egrep '^#*user' /etc/libvirt/qemu.conf),那么您必须对 /dev/vfio/<iommu_group> 具有正确的权限,例如 /dev/vfio/12。您必须调整 /etc/mdev.conf 或 udev 规则。另请注意,如果同一个 iommu 组中有多个 PCI 设备,您始终需要将所有设备添加到 VM,否则您将收到类似“Please ensure all devices within the iommu_group are bound to their vfio bus driver”的错误消息
# virsh dumpxml vm01 | xmllint --xpath '//*/hostdev' - <hostdev mode="subsystem" type="pci" managed="yes"> <driver name="vfio"/> <source> <address domain="0x0000" bus="0x02" slot="0x00" function="0x0"/> </source> <alias name="hostdev0"/> <address type="pci" domain="0x0000" bus="0x00" slot="0x06" function="0x0"/> </hostdev> <hostdev mode="subsystem" type="pci" managed="yes"> <driver name="vfio"/> <source> <address domain="0x0000" bus="0x02" slot="0x00" function="0x1"/> </source> <alias name="hostdev1"/> <address type="pci" domain="0x0000" bus="0x00" slot="0x08" function="0x0"/> </hostdev>
如果您直接使用 QEMU 而不使用 libvirt,并且尝试将 GPU 传递到您的 VM,则在以非 root 用户身份启动 VM 时,您可能会收到“VFIO_MAP_DMA failed: Out of memory”错误。解决此问题的一种方法是安装 shadow 软件包,并通过 /etc/security/limits.conf 文件增加用户可以锁定的内存量
# apk add shadow # echo "youruser soft memlock RAMamount \ youruser hard memlock RAMamount" >> /etc/security/limits.conf # reboot
将“youruser”替换为您希望运行 VM 的用户,将“RAMamount”替换为您的 VM 需要的 RAM 量(以 KB 为单位)。确切的数量最终可能会抛出相同的错误,因此您可能需要将此值增加几十 MB(通常 +40)。
关于 通过 OVMF 进行 PCI 直通的 Archwiki 文章 中提供了大量信息。