KVM

来自 阿尔派 Linux

KVM 是一个内核模块中的自由开源虚拟化解决方案。虽然它通常简称为 KVM,但实际的 hypervisor 是 QEMU。QEMU 从用户空间运行,但可以与 KVM 集成,通过利用内核空间的硬件来提供更好的性能。QEMU 可以虚拟化 x86、PowerPC 和 S390 客户机等。Libvirt 是一个管理框架,它与 QEMU/KVM、LXCXen 等集成。

安装

以下命令提供 libvirt 以及 用于 x86_64 仿真的 QEMUqemu-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.confudev 规则。另请注意,如果同一个 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 文章 中提供了大量信息。