libvirt (简体中文)
Libvirt 是一组软件的汇集,提供了管理虚拟机和其它虚拟化功能(如:存储和网络接口等)的便利途径。这些软件包括:一个长期稳定的 C 语言 API、一个守护进程(libvirtd)和一个命令行工具(virsh)。Libvirt 的主要目标是提供一个单一途径以管理多种不同虚拟化方案以及虚拟化主机,包括:KVM/QEMU,Xen,LXC,OpenVZ 或 VirtualBox hypervisors (详见这里)。
Libvirt 的一些主要功能如下:
- VM management(虚拟机管理):各种虚拟机生命周期的操作,如:启动、停止、暂停、保存、恢复和迁移等;多种不同类型设备的热插拔操作,包括磁盘、网络接口、内存、CPU等。
- Remote machine support(支持远程连接):Libvirt 的所有功能都可以在运行着 libvirt 守护进程的机器上执行,包括远程机器。通过最简便且无需额外配置的 SSH 协议,远程连接可支持多种网络连接方式。
- Storage management(存储管理):任何运行 libvirt 守护进程的主机都可以用于管理多种类型的存储:创建多种类型的文件镜像(qcow2,vmdk,raw,...),挂载 NFS 共享,枚举现有 LVM 卷组,创建新的 LVM 卷组和逻辑卷,对裸磁盘设备分区,挂载 iSCSI 共享,以及更多......
- Network interface management(网络接口管理):任何运行 libvirt 守护进程的主机都可以用于管理物理的和逻辑的网络接口,枚举现有接口,配置(和创建)接口、桥接、VLAN、端口绑定。
- Virtual NAT and Route based networking(虚拟 NAT 和基于路由的网络):任何运行 libvirt 守护进程的主机都可以管理和创建虚拟网络。Libvirt 虚拟网络使用防火墙规则实现一个路由器,为虚拟机提供到主机网络的透明访问。
安装
基于守护进程/客户端的架构的 libvirt 只需要安装在需要要实现虚拟化的机器上。注意,服务器和客户端可以是相同的物理机器。
服务端
安装 libvirt 以及至少一个虚拟运行环境(hypervisor):
- libvirt 的 KVM/QEMU 驱动 是 libvirt 的首选驱动,如果 KVM 功能已 启用,则支持全虚拟化和硬件加速的客户机。详见 QEMU。
- 其他受支持的虚拟运行环境,包括 LXC、VirtualBox 和 Xen。请参见它们各自的安装说明。
对于网络连接,安装这些包:
- iptables-nft 和 dnsmasq 用于 默认的 NAT/DHCP网络
- bridge-utils 用于桥接网络
- openbsd-netcat 通过 SSH 远程管理
客户端
客户端是用于管理和访问虚拟机的用户界面。
- virsh — virsh 是用于管理和配置域(虚拟机)的命令行程序。
- GNOME Boxes — 简单的 GNOME 3 程序,可以访问远程虚拟系统。
- Libvirt Sandbox — 应用程序沙箱工具包。
- Remote Viewer — 简单的远程访问工具。
- Qt VirtManager — 管理虚拟机的Qt程序。
- Virtual Machine Manager — 使用libvirt对KVM,Xen,LXC进行管理的图形化工具。
兼容 libvirt 的软件列表见 这里.
配置
对于系统 级别的管理任务(如:全局配置和镜像卷 位置),libvirt 要求至少要设置授权和启动守护进程。
设置授权
来自 libvirt:连接授权:
- Libvirt 守护进程允许管理员分别为客户端连接的每个网络 socket 选择不同授权机制。这主要是通过 libvirt 守护进程的主配置文件
/etc/libvirt/libvirtd.conf
来实现的。每个 libvirt socket 可以有独立的授权机制配置。目前的可选项有none
、polkit
和sasl
。
由于 libvirt 在安装时将把 polkit 作为依赖一并安装,所以 polkit 通常是 unix_sock_auth
参数的默认值(来源)。但基于文件的权限仍然可用。
使用 polkit
polkit
认证工作正常,应该重启一次系统。libvirt 守护进程在 polkit 策略配置文件(/usr/share/polkit-1/actions/org.libvirt.unix.policy
)中提供了两种策略(参阅:Polkit (简体中文)#操作):
-
org.libvirt.unix.manage
面向完全的管理访问(读写模式后台 socket),以及 -
org.libvirt.unix.monitor
面向仅监视察看访问(只读 socket)。
默认的面向读写模式后台 socket 的策略将请求认证为管理员。这点类似于 sudo 认证,但它并不要求客户应用最终以 root 身份运行。默认策略下也仍然允许任何应用连接到只读 socket。
Arch Linux 默认 wheel
组的所有用户都是管理员身份:定义于 /etc/polkit-1/rules.d/50-default.rules
(参阅:Polkit (简体中文)#管理员身份认证)。这样就不必新建组和规则文件。 如果用户是 wheel
组的成员:只要连接到了读写模式 socket(例如通过 virt-manager)就会被提示输入该用户的口令。
pkttyagent
它可能因工作不正常而导致各种问题。从 libvirt 1.2.16 版开始(提案见:[1]),libvirt
组的成员用户默认可以无口令访问读写模式 socket。最简单的判断方法就是看 libvirt 组是否存在并且用户是否该组成员。
你可能想要修改授权以读写模式访问socket的组,例如,你想授权kvm
组,可创建下面的文件:
/etc/polkit-1/rules.d/50-libvirt.rules
/* Allow users in kvm group to manage the libvirt daemon without authentication(允许 kvm 组的用户管理 libvirt 而无需认证) */ polkit.addRule(function(action, subject) { if (action.id == "org.libvirt.unix.manage" && subject.isInGroup("kvm")) { return polkit.Result.YES; } });
然后添加用户到 kvm
组并重新登录。kvm 也可以是任何其它存在的组并且用户是该组成员(详阅用户和用户组)。
修改组之后不要忘记重新登录才能生效。
基于文件的权限授权
为了给 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.service
和 virtlockd.socket
两个服务单元,因此后二者不必再设置为启用。
非加密的 TCP/IP sockets
编辑 /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"
用主机名访问虚拟机
在非隔离的、桥接的网络中从宿主机访问客户机,可以通过启用 libvirt 提供的 libvirt
NSS 模块实现。
编辑 /etc/nsswitch.conf
:
/etc/nsswitch.conf
hosts: files libvirt dns myhostname
ping
和 ssh
这类命令用于虚拟机主机名可以正常工作,但 host
和 nslookup
这类命令可能会失败或产生非预期结果,因后者依赖 DNS 。应改用 getent hosts <vm-hostname>
命令。测试
测试 libvirt 在系统级工作是否正常:
$ virsh -c qemu:///system
测试 libvirt 在用户会话级工作是否正常:
$ virsh -c qemu:///session
管理
绝大部分的 libvirt 管理可以通过三个工具实现:virt-manager(图形界面)、virsh
和 guestfish
(它是 libguestfs 的一部分)。
virsh
Visrsh 用于管理客户域(虚拟机),在脚本式虚拟化管理环境中工作良好。由于需要通过通讯管道与虚拟运行环境通讯,绝大部分 virsh 命令需要管理员权限。尽管如此,一些典型的管理操作如域的创建、运行等也可以像VirtualBox 那样以普通用户身份执行。
Virsh 允许带命令行选项执行。如果不带则进入其内置的交互式终端:virsh
。交互式终端支持 tab 键命令补全。
从命令行执行:
$ virsh [可选项] <命令> [参数]...
在交互式终端里运行:
virsh # <命令> [参数]...
帮助也是可用的:
$ virsh help [option*] or [group-keyword*]
存储池
存储池是指保存卷的位置。Libvirt 中卷的定义相当于其他系统中虚拟磁盘或虚拟机镜像的概念。存储池应该是一个目录、一个网络文件系统或一个分区(此处包括 LVM)。存储池可以在活动与不活动之间切换,可以为其分配存储空间。
在系统级别,默认被激活的存储池是 /var/lib/libvirt/images/
;在用户会话级别,virt-manager
将存储池创建在 $HOME/VirtualMachines
目录。
列出活动和不活动的存储池的命令:
$ 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 卷组不同的名字。否则当存储池被删除时,该卷组也将被删除。
用 virt-manager 新建存储池
首先,连接到虚拟运行环境(例如QEMU/KVM的系统/用户会话)。然后,右键点击一个连接(例如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.
virt-manager 后备存储类型的 bug
在较新版本的virt-manager
中,你可以在创建新磁盘的时候选择一个后备存储(backing store)。这个功能很实用,它可以在你创建新域的时候选择基础镜像,从而节省你的时间和磁盘空间。目前的virt-manager
有一个bug(https://bugzilla.redhat.com/show_bug.cgi?id=1235406),导致qcow2
格式的后备存储被错误的当做raw
格式。这会让虚拟机无法读取后备存储,从而使这个功能完全失效。
这里有一个临时的解决办法。qemu-img
长期以来都可以直接实现这个功能。如果你想在这个bug修复之前为新域创建一个后备存储,你可以使用下面的命令。
$ qemu-img create -f qcow2 -o backing_file=<path to backing image>,backing_fmt=qcow2 <disk name> <disk size>
之后你就可以以此镜像为基础创建新域,后备存储将被用作一个CoW(Copy on Write,写时复制)卷,节省你的时间和磁盘空间。
域
虚拟机被称作“域”。如果你想在命令行下操作,使用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
, 存储(--disk
, --filesystem
,或--nodisks
),和安装方法(通常来说是.iso
文件或CD)。查看virt-install(1)得到未列出的选项和更多的详情。
Arch Linux(两个虚拟CPU,1 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=raw \ --network user \ --virt-type kvm
Fedora testing (Xen, 非默认池,无默认控制台):
$ 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得到。要使用VirtIO,需要在虚拟机.xml
配置中使用<model type='virtio' />
更多的信息可以参考QEMU页面.导入现有的卷:
$ virt-install \ --name demo \ --memory 512 \ --disk /home/user/VMs/mydisk.img \ --import
用 virt-manager 新建域
首先,连接到虚拟运行环境(例如 QEMU/KVM system 或用户 session,在连接上右击并选择 新建,然后跟随向导完成。
- 在第四步中取消选中立即分配全部虚拟磁盘空间会加快创建过程并节省实际虚拟磁盘空间占用;然而,这将导致将来花费额外的磁盘整理时间。
- 在第五步中打开高级选项并确认虚拟化类型设为 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服务,运行中的域可以在宿主机关闭时自动挂起/关闭。同时这个服务还可以让挂起/休眠的域在宿主机启动的时候自动恢复。查看/etc/conf.d/libvirt-guests
并设置相关选项。
编辑一个域的XML配置:
$ virsh edit domain
网络
这里是有关 libvirt 网络的一个正宗的概述。
默认情况下,当 libvirtd
服务启动后,即创建了一个名为 default 的 NAT 网桥与外部网络联通(仅 IPv4)。对于其他的网络连接需求,可创建下列四种类型的网络以连接到虚拟机:
- bridge — 这是一个虚拟设备,它通过一个物理接口直接共享数据。使用场景为:宿主机有 静态 网络、不需与其它域连接、要占用全部进出流量,并且域运行于 系统 层级。有关如何在现有默认网桥时增加另一个网桥的方法,请参阅 网桥。网桥创建后,需要将它指定到相应客户机的
.xml
配置文件中。 - network — 这是一个虚拟网络,它可以与其它虚拟机共用。使用场景为:宿主机有 动态 网络(例如:NetworkManager)或使用无线网络。
- macvtap — 直接连接到宿主机的一个物理网络接口。
- user — 本地网络,仅用于用户 会话。
绝大多数用户都可以通过 virsh
的各种可选项创建具有各种功能的网络,一般来说比通过 GUI 程序(像 virt-manager
之类)更容易做到。也可以按 #用 virt-install 新建域 所述实现。
ip_forward
内核参数。这也意味着宿主机上已运行的dnsmasq并不是libvirt所必须的(并可能干扰到libvirt的dnsmasq实例)。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
改为你的物理接口的名称),并且重新启动系统。
/etc/sysctl.d/libvirt-bridge.conf
net.ipv6.conf.eth0.accept_ra = 2
快照
快照保存某一时刻域的磁盘、内存和设备状态以供将来使用。快照有很多用处,例如在进行可能的破坏性操作时保存一份干净的域状态。快照使用唯一名称进行标识。
快照保存在卷之中,卷必须为qcow2或raw格式。快照使用增量存储,所以并不会占用很多空间。
创建快照
Once a snapshot is taken it is saved as a new block device and the original snapshot is taken offline. Snapshots can be chosen from and also merged into another (even without shutting down the domain).
Print a running domain's volumes (running domains can be printed with virsh list
):
# virsh domblklist domain
Target Source ------------------------------------------------ vda /vms/domain.img
To see a volume's physical properties:
# 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
Create a disk-only snapshot (the option --atomic
will prevent the volume from being modified if snapshot creation fails):
# virsh snapshot-create-as domain snapshot1 --disk-only --atomic
List snapshots:
# virsh snapshot-list domain
Name Creation Time State ------------------------------------------------------------ snapshot1 2012-10-21 17:12:57 -0700 disk-snapshot
One can they copy the original image with cp --sparse=true
or rsync -S
and then merge the the original back into snapshot:
# virsh blockpull --domain domain --path /vms/domain.snapshot1
domain.snapshot1
becomes a new volume. After this is done the original volume (domain.img
and snapshot metadata can be deleted. The virsh blockcommit
would work opposite to blockpull
but it seems to be currently under development (including snapshot-revert feature
, scheduled to be released sometime next year.
其他管理操作
连接到非默认的虚拟运行环境:
$ virsh --connect xen:/// virsh # uri xen:///
通过SSH连接到QEMU虚拟运行环境,并且以相同方式登录:
$ 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(libvirt对VirtualBox的支持尚不稳定,可能会导致libvirtd崩溃):
$ virsh --connect vbox:///system
网络配置:
$ virsh -c qemu:///system net-list --all $ virsh -c qemu:///system net-dumpxml default
Python 连接代码
libvirt-python软件包提供了一个python2API,位于/usr/lib/python2.7/site-packages/libvirt.py
。
一般的例子在/usr/share/doc/libvirt-python-your_libvirt_version/examples/
给出。
一个qemu-desktop和openssh的例子(非官方):
#! /usr/bin/env python2 # -*- coding: utf-8 -*- import socket import sys import libvirt if (__name__ == "__main__"): 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 " + str(domainID) domServ = domConnect break
UEFI 支持
Libvirt 可以通过 qemu 和 OVMF 来支持 UEFI 虚拟机。
安装 edk2-ovmf 。
添加下面的内容到 /etc/libvirt/qemu.conf
。
/etc/libvirt/qemu.conf
nvram = [ "/usr/share/ovmf/x64/OVMF_CODE.fd:/usr/share/ovmf/x64/OVMF_VARS.fd" ]
- 重启
libvirtd
现在你可以创建一个 UEFI 虚拟机了。 你可以通过 virt-manager 来创建。当你进行到向导的最后一步时:
- 勾选在安装前自定义配置,之后点击完成。
- 在概况屏幕, 将固件改为'UEFI x86_64'。
- 点击开始安装
- 在启动屏幕,你需要使用linuxefi命令来启动安装程序,并且你需要在系统中运行efibootmgr验证确实运行在UEFI模式下。
参考fedora wiki获得更多信息。
PulseAudio
PulseAudio守护进程通常在你的普通用户下运行,并且只接受来自相同用户的连接。然而libvirt默认使用root运行QEMU。为了让QEMU在普通用户下运行,编辑/etc/libvirt/qemu.conf
并将user
设置为你的用户名。
user = "dave"
你同样需要告诉QEMU使用PulseAudio后端并识别要连接的服务器,首先将QEMU命名空间添加到你的域。
编辑域的.xml
文件(使用virsh edit domain
),将domain type
行改为:
<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'[失效链接 2020-08-02 ⓘ]>
并且加入如下的配置(在最后一个</devices>
之后,</domain>
之前):
<qemu:commandline> <qemu:env name='QEMU_AUDIO_DRV' value='pa'/> <qemu:env name='QEMU_PA_SERVER' value='/run/user/1000/pulse/native'/> </qemu:commandline>
1000
是你的用户ID,如果必要的话改为你的用户ID。