libvirt
Libvirt 是一个软件集合,它提供了一种管理虚拟机和其他虚拟化功能的便捷方法,例如存储和网络接口管理。这些软件部分包括一个长期稳定的 C API、一个守护进程 (libvirtd) 和一个命令行实用程序 (virsh)。libvirt 的主要目标是提供一种管理多种不同虚拟化提供程序/hypervisor 的单一方法,例如 KVM/QEMU、Xen、LXC、OpenVZ 或 VirtualBox hypervisor(以及其他)。
libvirt 的一些主要功能包括
- VM 管理:各种域生命周期操作,例如启动、停止、暂停、保存、恢复和迁移。针对多种设备类型的热插拔操作,包括磁盘和网络接口、内存和 CPU。
- 远程机器支持:所有 libvirt 功能都可以在运行 libvirt 守护进程的任何机器上访问,包括远程机器。支持多种网络传输方式进行远程连接,最简单的是 SSH,它不需要额外的显式配置。
- 存储管理:运行 libvirt 守护进程的任何主机都可以用于管理各种类型的存储:创建各种格式(qcow2、vmdk、raw 等)的文件映像,挂载 NFS 共享,枚举现有的 LVM 卷组,创建新的 LVM 卷组和逻辑卷,分区原始磁盘设备,挂载 iSCSI 共享等等。
- 网络接口管理:运行 libvirt 守护进程的任何主机都可以用于管理物理和逻辑网络接口。枚举现有接口,以及配置(和创建)接口、网桥、vlan 和 bond 设备。
- 虚拟 NAT 和基于路由的网络:运行 libvirt 守护进程的任何主机都可以管理和创建虚拟网络。Libvirt 虚拟网络使用防火墙规则充当路由器,为 VM 提供对主机网络透明的访问。
安装
由于其守护进程/客户端架构,libvirt 只需要安装在将托管虚拟化系统的机器上。请注意,服务器和客户端可以是同一物理机器。
服务器
安装 libvirt 软件包,以及至少一个 hypervisor
- libvirt KVM/QEMU 驱动程序是主要的 libvirt 驱动程序,如果 启用了 KVM,则完全虚拟化、硬件加速的 guest 将可用。有关更多信息,请参阅 QEMU 文章。
- 其他 支持的 hypervisor 包括 LXC、VirtualBox 和 Xen。有关安装说明,请参阅各自的文章。关于
libvirtd
安装说明
对于网络连接,请安装
- dnsmasq 以用于 默认 NAT/DHCP 网络。
- openbsd-netcat 以用于通过 SSH 进行远程管理。
其他可选依赖项可能会提供所需或扩展的功能,例如 dmidecode 用于 DMI 系统信息支持。在阅读 pacman 的 libvirt 输出后,作为依赖项 安装您可能需要的那些。
libvirt
5.1.0 和 firewalld 0.7.0 开始,您不再需要将防火墙后端更改为 iptables。libvirt
现在在 firewalld 中安装一个名为“libvirt”的区域,并在那里管理其所需的网络规则。请参阅 libvirt 中的防火墙和网络过滤。客户端
客户端是用于管理和访问虚拟机的用户界面。
- virsh — 用于管理和配置域的命令行程序。
- Boxes — 简单的 GNOME 应用程序,用于访问虚拟系统。属于 gnome-extra 的一部分。
- Libvirt Sandbox — 应用程序沙箱工具包。
- Virt Viewer — 简单的远程显示客户端。
- Virt-manager — 通过 libvirt 以图形方式管理 KVM、Xen 或 LXC。
- Cockpit — 基于 Web 的系统管理工具,带有用于管理虚拟机的插件。
可以在此处找到与 libvirt 兼容的软件列表。
配置
Libvirt 可以通过两种模式(系统和会话)管理 QEMU 虚拟机[1][2]
- 系统 URI 连接到以 root 身份运行的 libvirtd 守护进程,该守护进程在系统启动时启动。使用“系统”创建和运行的虚拟机通常以 root 身份启动,除非另有配置(例如在
/etc/libvirt/qemu.conf
中)。 - 会话 URI 以本地用户身份启动 libvirtd 实例,并且所有 VM 都以本地用户权限运行。
关于它们的优缺点
- 主机启动时的 VM 自动启动仅适用于“系统”,并且 root libvirtd 实例具有通过网桥或虚拟网络使用正确网络配置的必要权限。
qemu:///system
通常是 virt-manager 等工具的默认设置。
qemu:///session
有一个严重的缺点:由于 libvirtd 实例没有足够的权限,因此唯一的开箱即用网络选项是 qemu 的用户模式网络,它具有不明显的限制,因此不建议使用(有关 qemu 网络选项的更多信息)
qemu:///session
的优点是权限问题消失了:磁盘映像可以轻松存储在 $HOME 中,串行 PTY 由用户拥有等等。
对于系统级管理(即全局设置和映像卷位置),libvirt 至少需要设置授权和启动守护进程。
对于用户会话管理,不需要守护进程设置和配置;但是,授权仅限于本地能力;前端将启动 libvirtd 守护进程的本地实例。
设置身份验证
- libvirt 守护进程允许管理员为每个网络套接字独立选择用于客户端连接的身份验证机制。这主要通过
/etc/libvirt/libvirtd.conf
中的 libvirt 守护进程主配置文件来控制。每个 libvirt 套接字都可以独立配置其身份验证机制。目前有none
、polkit
和sasl
可供选择。
使用 libvirt 组
确保您的用户有权访问 libvirt 守护进程的最简单方法是将成员添加到 libvirt
用户组。
默认情况下,libvirt
组的成员可以无密码访问 RW 守护进程套接字。
使用 polkit
由于 libvirt 在安装期间拉取 polkit 作为依赖项,因此 polkit 用作 unix_sock_auth
参数的默认值(来源)。基于文件的权限仍然可用。
polkit
正确进行身份验证。libvirt 守护进程在 /usr/share/polkit-1/actions/org.libvirt.unix.policy
中提供两个 polkit 操作
org.libvirt.unix.manage
用于完全管理访问权限(RW 守护进程套接字),以及org.libvirt.unix.monitor
用于仅监视访问权限(只读套接字)。
RW 守护进程套接字的默认策略将要求以管理员身份进行身份验证。这类似于 sudo 身份验证,但不要求客户端应用程序最终以 root 身份运行。默认策略仍然允许任何应用程序连接到 RO 套接字。
Arch 默认将 wheel
组中的任何人视为管理员:这在 /usr/share/polkit-1/rules.d/50-default.rules
中定义(请参阅 Polkit#管理员身份)。因此,如果您的用户是 wheel
组的成员,则无需创建新的组和规则文件:连接到 RW 套接字时(例如通过 virt-manager),系统将提示您输入用户密码。
pkttyagent
代理的问题,该代理可能无法正常工作。您可以更改授权访问 RW 守护进程套接字的组。例如,要授权 mykvm
组,请创建以下文件
/etc/polkit-1/rules.d/50-libvirt.rules
/* Allow users in mykvm group to manage the libvirt daemon without authentication */ polkit.addRule(function(action, subject) { if (action.id == "org.libvirt.unix.manage" && subject.isInGroup("mykvm")) { return polkit.Result.YES; } });
然后 将自己添加到 mykvm
组并重新登录。将 mykvm 替换为您喜欢的任何组,只需确保它存在并且您的用户是其成员(有关更多信息,请参阅 用户和组)。
不要忘记重新登录以使组更改生效。
使用基于文件的权限进行身份验证
要为 libvirt 组中的用户定义基于文件的权限以管理虚拟机,请取消注释并定义
/etc/libvirt/libvirtd.conf
#unix_sock_group = "libvirt" #unix_sock_ro_perms = "0777" # set to 0770 to deny non-group libvirt users #unix_sock_rw_perms = "0770" #auth_unix_ro = "none" #auth_unix_rw = "none"
虽然一些指南提到了更改某些 libvirt 目录的权限以简化管理,但请记住,权限在软件包更新时会丢失。要编辑这些系统目录,需要 root 用户。
守护进程
启动 libvirtd.service
和 virtlogd.service
。可选地启用 libvirtd.service
(这也将启用 virtlogd.socket
和 virtlockd.socket
单元,因此不需要也启用 virtlogd.service
)。
另一种可能性是仅启动/启用 libvirtd.socket
和 virtlogd.socket
以进行按需套接字激活。
未加密的 TCP/IP 套接字
编辑 /etc/libvirt/libvirtd.conf
/etc/libvirt/libvirtd.conf
listen_tls = 0 listen_tcp = 1 auth_tcp="none"
还需要通过编辑 /etc/conf.d/libvirtd
以侦听模式启动服务器
/etc/conf.d/libvirtd
LIBVIRTD_ARGS="--listen"
使用虚拟机的主机名访问虚拟机
为了使主机能够访问非隔离的桥接网络上的 guest,请启用 libvirt 提供的 libvirt
和/或 libvirt_guest
NSS 模块。有关这两个模块的比较和技术细节,请参阅 libvirt 文档。
在 nsswitch.conf(5) 中添加所需的模块
/etc/nsswitch.conf
hosts: files libvirt libvirt_guest dns myhostname
ping
和 ssh
之类的命令应与虚拟机主机名一起使用,但诸如 host
和 nslookup
之类的命令可能会失败或产生意外结果,因为它们依赖于 DNS。请改用 getent hosts <vm-hostname>
。测试
要测试 libvirt 在系统级别是否正常工作
$ virsh -c qemu:///system
要测试 libvirt 对于用户会话是否正常工作
$ virsh -c qemu:///session
管理
Libvirt 管理主要通过三个工具完成:virt-manager (GUI)、virsh
和 guestfish
(它是 libguestfs 的一部分)。
virsh
virsh 程序用于管理 guest 域(虚拟机),并且非常适合脚本编写和虚拟化管理。虽然大多数 virsh 命令由于用于与 hypervisor 通信的通道而需要 root 权限才能运行,但域的典型管理、创建和运行(如 VirtualBox 所做的那样)可以作为普通用户完成。
如果未传递任何命令(但允许选项),Virsh 包括可以进入的交互式终端:virsh
。交互式终端支持 Tab 补全。
从命令行
$ virsh [option] <command> [argument]...
从交互式终端
virsh # <command> [argument]...
帮助可用
$ virsh help [option*] or [group-keyword*]
存储池
池是存储卷可以保存的位置。libvirt 定义为卷的内容,其他人可能定义为“虚拟磁盘”或“虚拟机映像”。池位置可以是目录、网络文件系统或分区(包括 LVM)。可以切换池的激活或非激活状态,并为其分配空间。
在系统级别,默认情况下将激活 /var/lib/libvirt/images/
;在用户会话中,virt-manager
创建 $XDG_DATA_HOME/images
。
打印活动和非活动存储池
$ virsh pool-list --all
使用 virsh 创建新池
如果想要添加存储池,以下是命令形式的示例,添加目录和添加 LVM 卷
$ virsh pool-define-as name type [source-host] [source-path] [source-dev] [source-name] [<target>] [--source-format format] $ virsh pool-define-as poolname dir - - - - /home/username/.local/libvirt/images $ virsh pool-define-as poolname fs - - /dev/vg0/images - mntpoint
上面的命令定义了池的信息,要构建它
$ virsh pool-build poolname $ virsh pool-start poolname $ virsh pool-autostart poolname
要删除它
$ virsh pool-undefine poolname
- 最好为存储池专门分配一个卷组。
- 选择与池名称不同的 LVM 卷组,否则,当存储池被删除时,LVM 组也会被删除。
使用 virt-manager 创建新池
首先,连接到 hypervisor(例如 QEMU/KVM 系统或用户会话)。然后,右键单击连接并选择详细信息;选择存储选项卡,按下左下角的 + 按钮,然后按照向导操作。
存储卷
创建池后,可以在池内创建卷。如果构建新的域(虚拟机),则可以跳过此步骤,因为可以在域创建过程中创建卷。
使用 virsh 创建新卷
创建卷、列出卷、调整大小和删除
$ virsh vol-create-as poolname volumename 10GiB --format aw|bochs|raw|qcow|qcow2|vmdk $ virsh vol-upload --pool poolname volumename volumepath $ virsh vol-list poolname $ virsh vol-resize --pool poolname volumename 12GiB $ virsh vol-delete --pool poolname volumename $ virsh vol-dumpxml --pool poolname volumename # for details.
域
虚拟机称为域。如果从命令行工作,请使用 virsh
列出、创建、暂停、关闭域等。virt-viewer
可用于查看使用 virsh
启动的域。域的创建通常通过图形方式使用 virt-manager
或使用 virt-install
(作为 virt-install 软件包的一部分安装的命令行程序)完成。
创建新域通常涉及使用一些安装介质,例如来自存储池或光驱的 .iso
。
打印活动和非活动域
# virsh list --all
/var/lib/libvirt/images/
中的卷。如果使用 SELinux 并且卷存在问题,请确保卷位于该目录中,或确保其他存储池已正确标记。使用 virt-install 创建新域
对于极其详细的域(虚拟机)设置,#使用 virt-manager 创建新域更容易。但是,基本操作可以轻松地通过 virt-install
完成,并且仍然可以运行良好。最低规格为 --name
、--memory
、guest 存储(--disk
、--filesystem
或 --nodisks
)以及安装方法(通常为 .iso
或 CD)。有关未列出的选项的更多详细信息和信息,请参阅 virt-install(1)。
Arch Linux 安装(两 GiB,qcow2 格式卷创建;用户网络)
$ virt-install \ --name arch-linux_testing \ --memory 1024 \ --vcpus=2,maxvcpus=4 \ --cpu host \ --cdrom $HOME/Downloads/arch-linux_install.iso \ --disk size=2,format=qcow2 \ --network user \ --virt-type kvm
Fedora 测试(Xen hypervisor,非默认池,最初不查看)
$ virt-install \ --connect xen:/// \ --name fedora-testing \ --memory 2048 \ --vcpus=2 \ --cpu=host \ --cdrom /tmp/fedora20_x84-64.iso \ --os-type=linux --os-variant=fedora20 \ --disk pool=testing,size=4 \ --network bridge=br0 \ --graphics=vnc \ --noautoconsole $ virt-viewer --connect xen:/// fedora-testing
Windows
$ virt-install \ --name=windows7 \ --memory 2048 \ --cdrom /dev/sr0 \ --os-variant=win7 \ --disk /mnt/storage/domains/windows7.qcow2,size=20GiB \ --network network=vm-net \ --graphics spice
osinfo-query --fields=name,short-id,version os
以获取 --os-variant
的参数;这将有助于定义域的一些规范。但是,--memory
和 --disk
将需要输入;如果需要这些规范,可以在相应的 /usr/share/libosinfo/db/oses/os.xml
中查找。安装后,最好安装 Spice Guest Tools,其中包括 VirtIO 驱动程序。对于 Windows VirtIO 网络驱动程序,还有 virtio-winAUR。这些驱动程序通过 guest 的设备 .xml
配置文件部分中的 <model type='virtio' />
引用。有关更多信息,请参见 QEMU 文章。导入现有卷
$ virt-install \ --name demo \ --memory 512 \ --disk /home/user/VMs/mydisk.img \ --import
使用 virt-manager 创建新域
首先,连接到 hypervisor(例如 QEMU/KVM 系统或用户会话),右键单击连接并选择新建,然后按照向导操作。
- 在第四步中,取消选择立即分配整个磁盘将使设置更快,并且可以节省临时磁盘空间;但是,随着时间的推移,它可能会导致卷碎片。
- 在第五步中,打开高级选项并确保虚拟化类型设置为 kvm(这通常是首选方法)。如果需要额外的硬件设置,请选择安装前自定义配置选项。
管理域
启动域
$ virsh start domain $ virt-viewer --connect qemu:///session domain
尝试正常关闭域;强制关闭域
$ virsh shutdown domain $ virsh destroy domain
在 libvirtd 启动时自动启动域
$ virsh autostart domain $ virsh autostart domain --disable
在主机关闭时关闭域
- 可以使用
libvirt-guests.service
systemd 服务在主机关闭时自动挂起/关闭正在运行的域。此服务将在主机启动时自动恢复/启动挂起/关闭的域。有关详细信息和服务选项,请参阅 libvirt-guests(8)。
编辑域的 XML 配置
$ virsh edit domain
要了解更多关于 XML 配置的信息,请阅读 libvirt wiki 的 XML 格式 部分。
网络
关于 libvirt 网络的全面概述。
存在四种网络类型,可以创建这些网络以将域连接到:
- bridge — 虚拟设备;直接与物理接口共享数据。如果主机具有静态网络,不需要连接其他域,域需要完整的入站和出站流量,并且域在系统级别上运行,则使用此类型。桥接必须在 libvirt 之外配置。请参阅网络桥接,了解如何添加桥接。创建后,需要在相应的访客机的
.xml
配置文件中指定它。 - network — 虚拟网络;能够与其他域共享。Libvirt 提供了许多虚拟网络模式,例如 NAT 模式(网络地址转换)、路由模式和隔离模式。如果主机具有动态网络(例如 NetworkManager)或使用无线网络,则尤其建议使用虚拟网络。
- macvtap — 直接连接到主机物理接口。这比 bridge 网络设置简单得多,唯一的缺点是主机无法通过此接口与域通信。Libvirt 可以轻松设置这种类型的网络。
- user — 本地能力网络。仅在用户会话中使用此类型。
virsh
具有创建网络的能力,并为大多数用户提供了众多选项,但是,使用图形用户界面(如 virt-manager
)创建网络连接更容易,或者在 使用 virt-install 创建 时这样做。
- libvirt 使用 dnsmasq 处理 DHCP 和 DNS,为每个虚拟网络启动一个单独的实例。它还添加了 iptables 规则以进行适当的路由,并启用了
ip_forward
内核参数。这也意味着,主机系统上运行 dnsmasq 对于支持 libvirt 要求不是必需的(并且可能会干扰 libvirt dnsmasq 实例)。 - 如果默认网络无法启动,请确保已安装 iptables-nft 和 dnsmasq,并且 iptables systemd 服务已启用。
$ systemctl start iptables.service $ systemctl enable iptables.service $ systemctl restart libvirtd.service
如果要使用 iptables 而不是 nftables,则需要在配置文件中相应地指定:/etc/libvirt/network.conf
。
示例:
# default: #firewall_backend = "nftables" firewall_backend = "iptables"
您可以通过以下方式获取 VM 的 IP 地址(如果它连接到 default
网络并通过 dhcp 接收 IP 地址):
$ virsh net-dhcp-leases default
命令(将 default
替换为 VM 连接的网络名称),或者如果 VM 运行了 qemu-guest-agent
,则通过:
$ virsh domifaddr --source agent $vm
将 $vm
替换为实际的虚拟机名称(或域 ID)。
管理和修改您的网络
要修改您的虚拟网络,强烈建议阅读 libvirt wiki 中的 虚拟网络的基本命令行用法 指南。还建议阅读 libvirt 网络 wiki,以了解更多关于其用法的知识。
IPv6
当通过任何配置工具添加 IPv6 地址时,您可能会收到以下错误:
Check the host setup: enabling IPv6 forwarding with RA routes without accept_ra set to 2 is likely to cause routes loss. Interfaces to look at: eth0
通过运行以下命令来修复此问题(将 eth0
替换为您的物理接口的名称):
# sysctl net.ipv6.conf.eth0.accept_ra=2
Macvtap
要设置 macvtap 网络,首先创建此文件:
macvtap.xml
<network> <name>macvtap-net</name> <forward mode='bridge'> <interface dev='eth0'/> </forward> </network>
然后,定义并启用网络:
$ virsh net-define macvtap.xml $ virsh net-autostart macvtap-net $ virsh net-start macvtap-net
现在,网络 macvtap-net
可用,并且在重启后仍然持久存在。它通过 eth0
桥接到外部网络。
nftables 防火墙
当将 NAT 网络类型与简单的限制性 nftables 防火墙(例如,默认配置)结合使用时,您可能需要允许转发到/从虚拟网络接口(默认配置在此处丢弃数据包)以及从虚拟网络接口到主机的 DHCP 客户端的 DNS/DHCP 请求。简化的示例,假设 virbr0
作为 libvirt 桥接接口:
/etc/nftables.conf
# ... table inet filter { chain input { type filter hook input priority filter policy drop # ... iifname virbr0 udp dport {53, 67} accept comment "allow VM dhcp/dns requests to host" # ... } chain forward { type filter hook forward priority filter policy drop iifname virbr0 accept oifname virbr0 accept } }
快照
快照在某个时间点获取域的磁盘、内存和设备状态,并将其保存以供将来使用。它们有许多用途,从保存操作系统映像的“干净”副本到在潜在的破坏性操作之前保存域的状态。快照使用唯一的名称进行标识。
快照保存在卷本身内,并且卷的格式必须为:qcow2 或 raw。快照使用增量,以便不占用像完整副本那样多的空间。
创建快照
一旦拍摄快照,它将被保存为新的块设备,并且原始快照将脱机。可以从快照中选择,也可以将快照合并到另一个快照中(即使在不关闭域的情况下)。
打印正在运行的域的卷(可以使用 virsh list
打印正在运行的域)
# virsh domblklist domain
Target Source ------------------------------------------------ vda /vms/domain.img
要查看卷的物理属性:
# qemu-img info /vms/domain.img
image: /vms/domain.img file format: qcow2 virtual size: 50G (53687091200 bytes) disk size: 2.1G cluster_size: 65536
创建仅磁盘快照(如果快照创建失败,--atomic
选项将阻止修改卷)
# virsh snapshot-create-as domain snapshot1 --disk-only --atomic
列出快照
# virsh snapshot-list domain
Name Creation Time State ------------------------------------------------------------ snapshot1 2012-10-21 17:12:57 -0700 disk-snapshot
然后可以使用 cp --sparse=true
或 rsync -S
复制原始映像,然后将原始映像合并回快照:
# virsh blockpull --domain domain --path /vms/domain.snapshot1
domain.snapshot1
成为新卷。完成此操作后,可以删除原始卷(domain.img
和快照元数据)。virsh blockcommit
的作用与 blockpull
相反,但它似乎目前正在开发中(包括 snapshot-revert feature
,计划在明年某个时候发布)。
其他管理
连接到非默认的 hypervisor
$ virsh --connect xen:/// virsh # uri xen:///
通过 SSH 连接到 QEMU hypervisor;记录日志的方式相同:
$ virsh --connect qemu+ssh://username@host/system $ LIBVIRT_DEBUG=1 virsh --connect qemu+ssh://username@host/system
通过 SSH 连接图形控制台:
$ virt-viewer --connect qemu+ssh://username@host/system domain $ virt-manager --connect qemu+ssh://username@host/system domain
连接到 VirtualBox hypervisor(libvirt 中的 VirtualBox 支持尚不稳定,可能会导致 libvirtd 崩溃)
$ virsh --connect vbox:///system
网络配置
$ virsh -c qemu:///system net-list --all $ virsh -c qemu:///system net-dumpxml default
钩子
钩子是在启动和运行 libvirt 守护程序时发生的各种事件触发的脚本。它们可用于执行启动访客机所需的准备命令,例如设置网络或保留内存。
存在以下钩子:
- daemon - 触发场合:start、shutdown、reload
- qemu - 触发场合:prepare、prepare、start、started、stopped、release、migrate、restore、reconnect、attach
- lxc - 触发场合:prepare、start、started、stopped、release、reconnect
- libxl - 触发场合:prepare、start、started、stopped、release migrate、reconnect
- network - 触发场合:start、started、stopped、port-created、updated、port-deleted
有关每个钩子和触发器的详细信息,请参阅 libvirt 文档。
创建钩子
钩子由位于 /etc/libvirt/hooks
的脚本表示。如果该文件夹不存在,则必须创建它。每个钩子都由该文件夹中具有相同名称的脚本(例如 /etc/libvirt/hooks/qemu
)或子文件夹(例如 /etc/libvirt/hooks/qemu.d/
)表示。后者可以包含不同的脚本,这些脚本都在触发点运行。这些脚本像任何其他脚本一样运行,因此它们需要以要使用的命令解释器的声明(例如 #!/bin/bash
)开头,并且需要由 libvirt 用户执行。
每次遇到触发点时,脚本都会运行。例如,守护程序脚本在系统的启动/停止周期中至少运行两次,分别在启动和关闭时运行。要在给定的点仅运行一个命令,您必须在脚本中实现条件。为此,libvirt 传递了可用于标识当前触发条件的参数。
根据 libvirt 文档,这些参数定义如下:
- 参数 1:操作中涉及的对象的名称
- 参数 2:正在执行的操作的名称
- 参数 3:如果要命名子操作,则使用此参数
- 参数 4:如果需要,额外的参数
如果其中一个参数不适用,则传递一个破折号。
示例
要在每次启动 qemu 访客机时,在分配任何资源之前运行命令,您可以使用 qemu 钩子。此时,libvirt 像这样运行钩子:/etc/libvirt/hooks/qemu <guest_name> prepare begin -
此脚本可能如下所示:
/etc/libvirt/hooks/qemu
#!/bin/bash guest_name="$1" libvirt_task="$2" if [ "$libvirt_task" = "prepare" ]; then <run some important code here> fi
如果访客机停止,则将运行相同的脚本,但是这次守护程序将像这样启动命令:/etc/libvirt/hooks/qemu <guest_name> stopped end -
在主机和访客机之间共享数据
Virtio-FS
此处的描述将使用巨页来启用共享文件夹的使用。使用 Virtio-FS 共享文件 列出了启用与访客机文件共享的受支持选项的概述。
首先,您需要启用巨页,这些巨页由虚拟机使用。
/etc/sysctl.d/40-hugepage.conf
vm.nr_hugepages = nr_hugepages
要确定所需的巨页数量,请检查巨页的大小:
$ grep Hugepagesize /proc/meminfo
巨页的数量为虚拟机内存大小 / 巨页大小。在此值上添加一些额外的页面。在此步骤之后,您必须重启,以便分配巨页。
现在,您必须准备虚拟机的配置:
# virsh edit name_of_virtual_machine
<domain> ... <memoryBacking> <hugepages/> </memoryBacking> ... <cpu ...> <numa> <cell memory='memory size of virtual machine' unit='KiB' memAccess='shared'/> </numa> </cpu> ... <devices> ... <filesystem type='mount' accessmode='passthrough'> <driver type='virtiofs'/> <source dir='path to source folder on host'/> <target dir='mount_tag'/> </filesystem> ... </devices> </domain>
有必要添加 NUMA 定义,以便可以将内存访问声明为共享。NUMA 的 id 和 cpus 值将由 virsh 插入。
现在应该可以在共享机器中挂载文件夹了:
# mount -t virtiofs mount_tag /mnt/mount/path
添加以下 fstab 条目以在启动时自动挂载文件夹:
/etc/fstab
... mount_tag /mnt/mount/path virtiofs rw,noatime,_netdev 0 0
9p
可以使用 9P 协议 共享文件系统目录。详细信息可在 QEMU 的 9psetup 文档 中找到。
按如下方式配置虚拟机:
<domain> ... <devices> ... <filesystem type="mount" accessmode="mapped"> <source dir="/path/on/host"/> <target dir="mount_tag"/> </filesystem> </devices> </domain>
启动访客机并使用以下命令从其中挂载共享目录:
# mount -t 9p -o trans=virtio,version=9p2000.L mount_tag /path/to/mount_point/on/guest
有关更多挂载选项,请参阅 https://docs.linuxkernel.org.cn/filesystems/9p.html。
要在启动时挂载它,请将其添加到访客机的 fstab:
/etc/fstab
... mount_tag /path/to/mount_point/on/guest 9p trans=virtio,version=9p2000.L 0 0
9p 传输的模块(即 trans=virtio
的 9pnet_virtio
)不会自动加载,因此从 /etc/fstab
挂载文件系统将失败,您将遇到类似 9pnet: Could not find request transport: virtio
的错误。解决方案是在启动期间预加载模块:
/etc/modules-load.d/9pnet_virtio.conf
9pnet_virtio
Samba / SMB
在访客机和主机之间共享数据的另一种简单方法是使用 smb 协议。虽然性能和延迟可能不如其他描述的方法好,但对于简单的任务(如在访客机之间传输简单的文件(如图像或文档))来说,它已经足够了。
smb 服务器可以直接在主机或访客机上设置,例如使用 Samba,从而无需专用文件服务器。Windows 访客机在安装后立即包含创建 smb 共享的功能(Microsoft 支持页面)。
在 linux 下访问共享的一种可能方法(从主机或访客机,取决于您在哪里安装了服务器)是在 fstab 中创建一个条目。需要 samba 软件包。
/etc/fstab
#Accessing a samba share on my vm from the host //my_vm/my_share /home/archuser/my_vm cifs _netdev,noauto,nofail,user,credentials=/home/archuser/.config/my_vm.key,gid=1000,uid=984 0 0
_netdev,noauto,nofail
确保仅在需要时挂载共享,而不会在 vm 未启动时引起问题。user,credentials=/home/user/.config/my_vm.key,gid=1000,uid=984
使您能够在首次访问时动态挂载共享,而无需密码。
UEFI 支持
Libvirt 可以通过 QEMU 和 OVMF 支持 UEFI 虚拟机。
安装 edk2-ovmf 软件包。
重启 libvirtd
。
现在您可以创建 UEFI 虚拟机了。通过 virt-manager 创建新的虚拟机。当您到达新建 VM 向导的最后一页时,执行以下操作:
- 单击安装前自定义配置,然后选择完成。
- 在概述屏幕中,将固件字段更改为:
- UEFI x86_64: /usr/share/edk2/x64/OVMF_CODE.4m.fd 用于不带安全启动支持的 x64 UEFI,
- UEFI x86_64: /usr/share/edk2/x64/OVMF_CODE.secboot.4m.fd 用于带安全启动支持的 x64 UEFI(不带任何预先注册的证书)。
- 单击应用。
- 单击开始安装。
有关更多信息,请参阅 Fedora:Using UEFI with QEMU。
技巧和窍门
在虚拟机内部使用整个物理磁盘设备
您可能有一个带有不同操作系统(例如 Windows)的辅助磁盘,并且可能希望获得在虚拟机内部启动它的能力。由于磁盘访问是原始的,因此磁盘在虚拟机内部的性能将相当好。
Windows 虚拟机启动先决条件
在尝试在虚拟机中启动该磁盘上的操作系统之前,请务必在该操作系统内部安装 virtio 驱动程序。对于 Win 7,请使用版本 0.1.173-4。较新 virtio 构建中的一些单独驱动程序可以在 Win 7 上使用,但是您必须通过设备管理器手动安装它们。对于 Win 10,您可以使用最新的 virtio 构建。
设置 Windows 磁盘接口驱动程序
当尝试启动虚拟机时,您可能会遇到 0x0000007B
蓝屏。这意味着 Windows 在早期启动阶段无法访问驱动器,因为启动驱动器所需的磁盘接口驱动程序未加载/设置为手动启动。
解决方案是启用这些驱动程序以在启动时启动。
在 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
中,找到文件夹 aliide, amdide, atapi, cmdide, iastor (可能不存在), iastorV, intelide, LSI_SAS, msahci, pciide 和 viaide
。在每个文件夹中,将其所有“start”值设置为 0,以便在启动时启用它们。如果您的驱动器是 PCIe NVMe 驱动器,也请启用该驱动程序(如果存在)。
查找磁盘的唯一路径
运行 ls /dev/disk/by-id/
:在那里,您挑选出要插入虚拟机的驱动器的 ID,例如 ata-TS512GMTS930L_C199211383
。现在将该 ID 添加到 /dev/disk/by-id/
,以便您获得 /dev/disk/by-id/ata-TS512GMTS930L_C199211383
。那是该磁盘的唯一路径。
在 QEMU CLI 中添加磁盘
在 QEMU CLI 中,这可能是:
-drive file=/dev/disk/by-id/ata-TS512GMTS930L_C199211383,format=raw,media=disk
只需修改 file=
以成为您的驱动器的唯一路径。
在 libvirt 中添加磁盘
在 libvirt XML 中,这转换为:
$ virsh edit vmname
... <disk type="block" device="disk"> <driver name="qemu" type="raw" cache="none" io="native"/> <source dev="/dev/disk/by-id/ata-TS512GMTS930L_C199211383"/> <target dev="sda" bus="sata"/> <address type="drive" controller="0" bus="0" target="0" unit="0"/> </disk> ...
只需修改 “source dev” 以成为您的驱动器的唯一路径。
在 virt-manager 中添加磁盘
创建虚拟机时,选择“导入现有驱动器”并粘贴该唯一路径。如果您已经拥有虚拟机,请添加设备、存储,然后选择或创建自定义存储。现在粘贴唯一路径。
Python 连接代码
libvirt-python 软件包在 /usr/lib/python3.x/site-packages/libvirt.py
中提供了 Python API。
通用示例在 /usr/share/doc/libvirt-python-your_libvirt_version/examples/
中给出。
使用 qemu-desktop 和 openssh 的非官方示例:
#! /usr/bin/env python3 import socket import sys import libvirt conn = libvirt.open("qemu+ssh://xxx/system") print("Trying to find node on xxx") domains = conn.listDomainsID() for domainID in domains: domConnect = conn.lookupByID(domainID) if domConnect.name() == 'xxx-node': print("Found shared node on xxx with ID {}".format(domainID)) domServ = domConnect break
高级格式 4K 原生磁盘
要将磁盘转换为 高级格式 4Kn 磁盘,需要将其物理和逻辑扇区大小都设置为 4 KiB。对于 virtio-blk 和 virtio-scsi,可以通过使用 <blockio> 元素 设置 logical_block_size
和 physical_block_size
选项来完成此操作。例如:
# virsh edit name_of_virtual_machine
<domain> ... <devices> ... <disk type='file' device='disk'> .. <blockio logical_block_size='4096' physical_block_size='4096'/> </disk> ... </devices> </domain>
命令 QEMU
Libvirt 能够将 QEMU 命令行参数传递给运行 VM 的底层 QEMU 实例。当 libvirt 尚未提供 QEMU 功能 时,此功能非常有用。有关示例,请参阅完整的 Intel GVT-g 文章。
修改 VM XML 模式以用于 QEMU
这用于启用 QEMU 特定的元素。更改:
$ virsh edit vmname
<domain type='kvm'>
为:
$ virsh edit vmname
<domain xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0' type='kvm'>
QEMU 命令行参数
在 libvirt 中,以空格分隔的 QEMU 命令行参数需要单独提供。
插入它们的正确位置是在 <domain>
元素的末尾,即在结束标记 </domain>
的正上方。
-display gtk,gl=es,zoom-to-fit=off
变为:
$ virsh edit vmname
... </devices> <qemu:commandline> <qemu:arg value="-display"/> <qemu:arg value="gtk,gl=es,zoom-to-fit=off"/> </qemu:commandline> </domain>
故障排除
系统实例上的 PulseAudio
PulseAudio 守护程序通常在您的常规用户帐户下运行,并且仅接受来自同一用户的连接。如果 QEMU 通过 libvirt 以 root 用户身份运行,这可能会成为问题。要以常规用户身份运行 QEMU,请编辑 /etc/libvirt/qemu.conf
并将 user
选项设置为您的用户名。
user = "dave"
您还需要告知 QEMU 使用 PulseAudio 后端并标识要连接的服务器。使用 virsh edit
将以下部分添加到您的域配置中。
<audio id="1" type="pulseaudio" serverName="/run/user/1000/pulse/native"> <input latency="20000"/> <output latency="20000"/> </audio>
1000
是您的用户 ID。如有必要,请更改它。
您可以省略延迟设置(以微秒为单位),但是使用默认值可能会导致爆裂声。
Hypervisor CPU 使用率
virt-manager 生成的默认 VM 配置可能会导致 QEMU 进程引起的 CPU 使用率相当高(10-20%)。如果您计划在无头模式下运行 VM,请考虑删除一些不必要的设备。
虚拟机无法在 virt-manager 上取消暂停
如果您使用的是磁盘映像格式(例如 qcow2),它具有指定的虚拟容量,但仅存储所需的容量,那么您需要在主机分区上留出空间以供映像增长。如果您在尝试启动 VM 时看到 I/O 相关错误,则可能是保存虚拟磁盘映像的主机分区已满。您可以在主机上运行 df -h
以验证有多少可用空间。
如果是这种情况,请参阅 系统维护#清理文件系统,了解释放空间的方法。
在 virt-manager 中,“重定向 USB 设备” 菜单项灰显
如果重定向 USB 设备菜单项灰显,请检查是否为 VM 配置了以下硬件:
- USB 控制器。
- 一个或多个 USB 重定向器。
启动域时出错:请求的操作无效
当您尝试打开虚拟机时,可能会弹出此错误。这是因为当您尝试打开现有虚拟机时,libvirt 尝试搜索不可用的默认网络。要使其可用,您必须自动启动您的网络接口,以便在您重启计算机时,您的网络接口始终处于活动状态。请参阅 libvirt 网络页面。
使用以下命令查看您的网络接口的名称:
# virsh net-list --all
要自动启动您的网络接口:
# virsh net-autostart name_of_the_network
要启动您的网络接口:
# virsh net-start name_of_the_network
Virt Manager 错误“Virt Manager 没有搜索权限”
确保包含您的虚拟机文件和安装 ISO 的文件夹归 libvirt-qemu
组所有:
$ sudo chown -R $USER:libvirt-qemu /path/to/virtual/machine
启动域时出错:请求的操作无效:网络 'default' 未激活
如果由于任何原因默认网络被停用,您将无法启动任何配置为使用该网络的访客虚拟机。您的第一次尝试可以是简单地尝试使用 virsh 启动网络:
# virsh net-start default
有关其他故障排除步骤,请参阅 [3]。