KVM虚拟化:(四)libvirt简介与客户机配置

admin 2022年09月11日 2,111次浏览

1、libvirt简介

libvirt 是为了更方便地管理平台虚拟化技术而设计的开放源代码的应用程序接口、守护进程和管理工具,它不仅提供了对虚拟化客户机的管理,也提供了对虚拟化网络和存储的管理。libvirt 支持多种虚拟化方案,既支持包括 KVM、QEMU、Xen、VMware、VirtualBox、Hyper-V 等在内的平台虚拟化方案,也支持 OpenVZ、LXC 等Linux 容器虚拟化系统,还支持用户态 Linux(UML)的虚拟化

libvirt 作为中间适配层,可以让底层 Hypervisor 对上层用户空间的管理工具是完全透明的,因为 libvirt 屏蔽了底层各种 Hypervisor 的细节,为上层管理工具提供了一个统一的、较 稳定的接口(API)。通过 libvirt,一些用户空间管理工具可以管理各种不同的 Hypervisor 和上面运行的客户机,它们之间基本的交互框架如图所示

在 libvirt 中涉及几个重要的概念:

  • 节点(Node)是一个物理机器,上面可能运行着多个虚拟客户机,Hypervisor 和 Domain 都运行在节点上

  • Hypervisor 也称虚拟机监控器(VMM),如 KVM、Xen、VMware、Hyper-V 等,是虚拟化中的一个底层软件层,它可以虚拟化一个节点让其运行多个虚拟客户机

  • 域(Domain)是在 Hypervisor 上运行的一个客户机操作系统实例节点、Hypervisor 和域的关系可以简单地用下图来表示

2、libvirt的管理功能

  • 域的管理

    包括对节点上的域的各个生命周期的管理,如启动、停止、暂停、保 存、恢复和动态迁移。还包括对多种设备类型的热插拔操作,包括磁盘、网卡、内存和CPU

  • 远程节点的管理

    只要物理节点上运行了 libvirtd 这个守护进程,远程的管理程序就可以连接到该节点进程管理操作,经过认证和授权之后,所有的 libvirt 功能都可以被访问和使用。libvirt 支持多种网络远程传输类型,如SSH、TCP套接字、Unix domain socket、TLS 的加密传输等。假设使用了最简单的 SSH,不需要额外的配置工作,比如,在 example.com 节点上运行了 libvirtd,而且允许 SSH 访问,在远程的某台管理机器上就可以用如下的命令行来连接到 example.com 上,从而管理其上的域

    virsh -c qemu+ssh://root@example.com/system
    
  • 存储的管理

    任何运行了 libvirtd 守护进程的主机,都可以通过 libvirt 来管理不同类型的存储,如创建不同格式的客户机镜像(qcow2、raw、qde、vmdk等)、挂载 NFS 共享存储系统、查看现有的 LVM 卷组、创建新的 LVM 卷组和逻辑卷、对磁盘设备分区、挂载 iSCSI 共享存储、使用 Ceph 系统支持的 RBD 远程存储等等。当然在 libvirt中,对存储的管理也是支持远程的

  • 网络的管理

    任何运行了 libvirtd 守护进程的主机,都可以通过 libvirt 来管理物理的和逻辑的网络接口。包括列出现有的网络接口卡,配置网络接口,创建虚拟网络接口,网络接口的桥接,VLAN 管理,NAT 网络设置,为客户机分配虚拟网络接口等等

  • 提供一个稳定、可靠、高效的应用程序接口,以便可以完成前面的4个管理功能

3、libvirt的组成

libvirt 主要由3个部分组成,分别是:应用程序编程接口库、一个守护进程(libvirtd)和一个默认命令行管理工具(virsh)

  • 应用程序接口:是为其他虚拟机管理工具(如 virsh、virt-manager 等)提供虚拟机管理的程序库支持
  • libvirtd 守护进程:负责执行对节点上的域的管理工作,在用各种工具对虚拟机进行管理时,这个守护进程一定要处于运行状态中。而且这个守护进程可以分为两种:一种是 root 权限的 libvirtd,其权限较大,可以完成所有支持的管理工作;一种是普通用户权限的 libvirtd,只能完成比较受限的管理工作
  • virsh:virsh 是 libvirt 项目中默认的对虚拟机管理的一个命令行工具

4、libvirt的安装与配置

4.1、安装libvirt

# 安装libvirt
[root@kvm user]# yum install libvirt -y

# 查看系统是否安装libvirt
[root@kvm user]# rpm -qa | grep libvirt
libvirt-4.5.0-36.el7_9.5.x86_64
libvirt-client-4.5.0-36.el7_9.5.x86_64
libvirt-daemon-driver-qemu-4.5.0-36.el7_9.5.x86_64
libvirt-daemon-kvm-4.5.0-36.el7_9.5.x86_64
(....其他省略....)

4.2、libvirt的配置文件

libvirt 相关的配置文件在 /etc/libvirt/ 目录之中,其中比较关键的几个如下

  • /etc/libvirt/libvirt.conf

    libvirt.conf 文件用于配置一些常用 libvirt 连接(通常是远程连接)的别名

    # 将qemu+ssh://root@10.0.2.15/system配置为centos7别名
    [root@kvm ~]# cat /etc/libvirt/libvirt.conf | grep -v '^#' | grep -v '^$'
    uri_aliases = [
        "centos7=qemu+ssh://root@10.0.2.15/system",
    ]
    
    [root@kvm user]# systemctl reload libvirtd
    
    
  • /etc/libvirt/libvirtd.conf

    libvirtd.conf 是 libvirt 的守护进程 libvirtd 的配置文件,被修改后需要让 libvirtd 重新加载配置文件才会生效。在 libvirtd.conf 中配置了 libvirtd 启动时的许多设置,包括是否建立 TCP、UNIX domain socket 等连接方式及其最大连接数,以及这些连接的认证机制,设置 libvirtd 的日志级别等

  • /etc/libvirt/qemu.conf

    qemu.conf 是 libvirt 对 QEMU 的驱动的配置文件,包括 VNC、SPICE 等,以及连接它们时采用的权限认证方式的配置,也包括内存大页、SELinux、Cgroups 等相关配置

  • /etc/libvirt/qemu/目录

    在qemu目录下存放的是使用QEMU驱动的域的配置文件

4.3、libvirtd的使用

libvirtd 是一个作为 libvirt 虚拟化管理系统中的服务器端的守护程序,要让某个节点能够利用 libvirt 进行管理,都需要在这个节点上运行 libvirtd 这个守护进程,以便让其他上层管理工具可以连接到该节点,libvirtd 负责执行他管理工具发送给它的虚拟化管理操作指令。而 libvirt 的客户端工具(包括 virsh、virt-manager 等)可以连接到本地或远程的 libvirtd 进程,以便管理节点上的客户机(启动、关闭、重启、迁移等)、收集节点上的宿主机和客户机的配置和资源使用状态

在默认情况下,libvirtd 在监听一个本地的 Unix domain socket,而没有监听基于网络的 TCP/IP socket,需要使用 “-l 或 --listen” 的命令行参数来开启对 libvirtd.conf 配置文件中 TCP/IP socket 的配置。另外,libvirtd 守护进程的启动或停止,并不会直接影响正在运行中的客户机。libvirtd 在启动或重启完成时,只要客户机的 XML 配置文件是存在的,libvirtd 会自动加载这些客户的配置,获取它们的信息。当然,如果客户机没有基于 libvirt 格式的 XML 文件来运行(例如直接使用qemu命令行来启动的客户机),libvirtd 则不能自动发现它

常用 libvirtd 命令行参数

  • -d(–daemon)

    表示让 libvirtd 作为守护进程在后台运行

  • -f(–config FILE)

    指定 libvirtd 的配置文件为 FILE,而不是使用默认值(通常是 /etc/libvirt/libvirtd.conf)

  • -l(–listen)

    开启配置文件中配置的TCP/IP连接。

  • -p(–pid-file FILE)

    将 libvirtd 进程的 PID 写入 FILE 文件中,而不是使用默认值(通常是 /var/run/libvirtd.pid)

  • -t(–timeout SECONDS)

    设置对 libvirtd 连接的超时时间为 SECONDS 秒

  • -v(–verbose)

    执行命令输出详细的输出信息

  • –version

    显示 libvirtd 程序的版本信息

5、libvirt客户机(域)的XML配置文件

在使用 libvirt 对虚拟化系统进行管理时,很多地方都是以 XML 文件作为配置文件的,包括客户机(域)的配置、宿主机网络接口配置、网络过滤、各个客户机的磁盘存储配置、磁盘加密、宿主机和客户机的CPU特性等等,配置文件的存放位置在:/etc/libvirt/qemu/,配置文件的大概结构如下

<domain>
    各配置标签
</domain>

以下示例配置文件名称为:centos7.xml

5.1、CPU配置

<vcpu placement='static'>2</vcpu>
<features>
    <acpi/>
    <apic/>
</features>
<cpu mode='custom' match='exact'>
    <model fallback='allow'>Haswell-noTSX</model>
</cpu>

标签说明:

  • vcpu

    vCPU 的数量

  • features

    表示 Hypervisor 为客户机打开或关闭 CPU 或其他硬件的特性,这里打开了 ACPI、APIC 等特性

  • CPU mode

    CPU模型的配置

    • custom模式: 基于某个基础的 CPU 模型,再做个性化的设置

    • host-model模式: 根据物理 CPU 的特性,选择一个与之最接近的标准 CPU 型号,如果没有指定 CPU 模式,默认采用这种模式。xml 配置文件为:<cpu mode=‘host-model’/>

    • host-passthrough模式: 直接将物理 CPU 特性暴露给虚拟机使用,在虚拟机上看到的完全就是物理CPU的型号。xml配置文件为:<cpu mode=‘host-passthrough’/>

5.2、内存配置

<memory unit='KiB'>2097152</memory>
<currentMemory unit='KiB'>2097152</currentMemory>
  • memory标签

    表示客户机最大可使用的内存

  • currentMemory标签

    表示启动时即分配给客户机使用的内存。在使用 QEMU / KVM 时,一般将二者设置为相同的值

5.3、系统类型和启动顺序

<os>
    <type arch='x86_64' machine='pc'>hvm</type>
    <boot dev='hd'/>
    <boot dev='cdrom'/>
</os>

该配置表示客户机类型是 hvm 类型,因为 KVM 一定要依赖于硬件虚拟化技术的支持,所以在 KVM 中,客户机类型应该总是 hvm,操作系统的架构是 x86_64,机器类型是 pc。boot 选项用于设置客户机启动时的设备,这里有 hd 和 cdrom两种,而且是按照硬盘、光驱的顺序启动的,它们在 XML 配置文件中的先后顺序即启动时的先后顺序

5.4、网络配置

5.4.1、桥接方式

<devices>
    ...
    <interface type='bridge'>
    <mac address='52:54:00:e9:e0:3b'/>
    <source bridge='br0'/>
    <model type='virtio'/>
    <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
    </interface>
    ...
</devices>
  • <interface type=‘bridge’ >: 表示使用桥接方式使客户机获得网络
  • <mac address>: 用于配置客户机中网卡的 MAC 地址
  • <source bridge=‘br0’/>: 表示使用宿主机中的 br0 网络接口来建立网桥
  • <model type=‘virtio’/>: 表示在客户机中使用 virtio-net 驱动的网卡设备,也配置了该网卡在客户机中的 PCI 设备编号为 0000:00:03.0

5.4.2、NAT方式

<devices>
    ...
    <interface type='network'>
    <mac address='52:54:00:32:7d:f6'/>
    <source network='default'/>
    <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
    </interface>
    ...
</devices>

这里 <interface type=‘network’><source network=‘default’/> 表示使用 NAT 的方式,并使用默认的网络配置,客户机将会分配到 192.168.122.0/24 网段中的一个 IP 地址。当然,使用 NAT 必须保证宿主机中运行着 DHCP 和DNS 服务器,一般默认使用 dnsmasq 软件查询。查询 DHCP 和 DNS 服务的运行的命令行如下

[root@kvm img_dir]#  ps -ef | grep dnsmasq
nobody    1826     1  0 9月09 ?       00:00:00 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf --leasefile-ro --dhcp-script=/usr/libexec/libvirt_leaseshelper
root      1827  1826  0 9月09 ?       00:00:00 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf --leasefile-ro --dhcp-script=/usr/libexec/libvirt_leaseshelper

由于配置使用了默认的 NAT 网络配置,可以在 libvirt 相关的网络配置中看到一个 default.xml 文件(/etc/libvirt/qemu/networks/default.xml),它具体配置了默认的连接方式,如下:

<network>
    <name>default</name>
    <bridge name="virbr0" />
    <forward/>
    <ip address="192.168.122.1" netmask="255.255.255.0">
        <dhcp>
            <range start="192.168.122.2" end="192.168.122.254" />
        </dhcp>
    </ip>
</network>

在使用 NAT 时,查看宿主机中网桥的使用情况如下:

[root@kvm img_dir]# brctl show
bridge name     bridge id               STP enabled     interfaces
virbr0          8000.525400f280c2       yes             virbr0-nic

其中 vnet0 这个网络接口就是客户机和宿主机网络连接的纽带

5.4.3、用户模式

<devices>
    ...
    <interface type='user'>
        <mac address="00:11:22:33:44:55"/>
    </interface>
    ...
</devices>

<interface type=‘user’> 表示该客户机的网络接口是用户模式网络,是完全由 QEMU 软件模拟的一个网络协议栈。在宿主机中,没有一个虚拟的网络接口连接到 virbr0 这样的网桥

5.4.4、网卡设备直接分配(VT-d)

在客户机的网络配置中,还可以采用 PCI/PCI-e 网卡将设备直接分配给客户机使用

5.5、存储配置

<devices>
    ...
    <disk type='file' device='disk'>
        <driver name='qemu' type='raw' cache='none'/>
        <source file='/img_dir/centos7.img'/>
        <target dev='sda' bus='scsi'/>
    </disk>
    ...
</devices>

使用 img 格式的 centos7.img 镜像文件作为客户机的磁盘,其在客户机中使用 virtio 总线,设备名称为 /dev/vda,其 PCI 地址为 0000:00:07.0

  • <disk>标签

    客户机磁盘配置的主标签,其中包含它的属性和一些子标签。它的 type 属性表示磁盘使用哪种类型作为磁盘的来源,其取值为 file、block、dir 或 network 中的一个,分别表示使用文件、块设备、目录或网络作为客户机磁盘的来源。它的 device 属性表示让客户机如何来使用该磁盘设备,其取值为 floppy、disk、cdrom 或lun 中的一个,分别表示软盘、硬盘、光盘和 LUN(逻辑单元号),默认值为 disk(硬盘)。在 <disk> 标签中可以配置许多子标签

  • <driver>子标签

    用于定义 Hypervisor 如何为该磁盘提供驱动,它的 name 属性用于指定宿主机中使用的后端驱动名称,QEMU/KVM 仅支持 name=‘qemu’,但是它支持的类型 type 可以是多种,包括 raw、qcow2、qed、bochs 等。而这里的cache属性表示在宿主机中打开该磁盘时使用的缓存方式,可以配置为 default、none、writethrough、writeback、directsync 和 unsafe 等多种模式

  • <source>子标签

    表示磁盘的来源,当 <disk> 标签的 type 属性为 file 时,应该配置为 <source file=‘/img_dir/centos7.img’/> 这样的模式,而当 type 属性为 block 时,应该配置为 <source dev=‘/dev/sda’/> 这样的模式

  • <target>子标签

    表示将磁盘暴露给客户机时的总线类型和设备名称。其 dev 属性表示在客户机中该磁盘设备的逻辑设备名称,而 bus 属性表示该磁盘设备被模拟挂载的总线类型,bus 属性的值可以为 ide、scsi、virtio、xen、usb、sata 等。如果省略了 bus 属性,libvirt 则会根据 dev 属性中的名称来“推测” bus 属性的值,例如: sda 会被推测是 scsi,而 vda 被推测是virtio

  • <address>子标签

    表示该磁盘设备在客户机中的 PCI 总线地址,如果该标签不存在,libvirt 会自动分配一个地址

5.6、其他配置简介

5.6.1、域的配置

在域的整个XML配置文件中,<domain> 标签是范围最大、最基本的标签,是其他所有标签的根标签

<domain type='kvm'>
    ...
</domain>

在 <domain> 标签中可以配置两个属性:一个是 type,用于表示 Hypervisor 的类型,可选的值为 xen、kvm、qemu、lxc、kqemu、VMware 中的一个;另一个是 id,其值是一个数字,用于在该宿主机的 libvirt 中唯一标识一个运行着的客户机,如果不设置 id 属性,libvirt 会按顺序分配一个最小的可用 ID

5.6.2、域的元数据配置

在域的 XML 文件中,有一部分是用于配置域的元数据(meta data),元数据用于表示域的属性(用于区别其他的域),例如:

<name>centos7</name>
<uuid>2f6260bf-1283-4933-aaef-fa82148537ba</uuid>

name 用于表示该客户机的名称,uuid 是唯一标识该客户机的 UUID。在同一个宿主机上,各个客户机的名称和 UUID 都必须是唯一的

5.6.3、QEMU模拟器的配置

在域的配置文件中,需要制定使用的设备模型的模拟器,在emulator标签中配置模拟器的绝对路径

<devices>
    <emulator>/usr/libexec/qemu-kvm</emulator>
    ...
</devices>

5.6.4、图形显示方式(VNC)

<devices>
    ...
    <graphics type='vnc' port='-1' autoport='yes'/>
    ...
</devices>

这表示通过 VNC 的方式连接到客户机,其 VNC 端口为 libvirt 自动分配。也可以支持其他多种类型的图形显示方式,以下就配置了 SDL、VNC、RDP、SPICE 等多种客户机显示方式

<devices>
    ...
    <graphics type='sdl' display=':0.0'/>
    <graphics type='vnc' port='5904'>
        <listen type='address' address='1.2.3.4'/>
    </graphics>
    <graphics type='rdp' autoport='yes' multiUser='yes' />
    <graphics type='desktop' fullscreen='yes'/>
    <graphics type='spice'>
        <listen type='network' network='rednet'/>
    </graphics>
    ...
</devices>

5.6.5、客户机声卡和显卡的配置

<devices>
    ...
    <sound model='ich6'>
        <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/
                 </sound>
    <video>
        <model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='1'/>
        <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/
                 </video>
    ...
</devices>
  • <sound> 标签

    表示的是声卡配置,其中 model 属性表示为客户机模拟出来的声卡的类型,其取值为 es1370、sb16、ac97 和 ich6 中的一个

  • <video>标签

    表示的是显卡配置,其中 <model> 子标签表示为客户机模拟的显卡的类型,它的类型(type)属性可以为 vga、cirrus、vmvga、xen、vbox、qxl 中的一个,vram 属性表示虚拟显卡的显存容量(单位为KB),heads 属性表示显示屏幕的序号。本示例中,KVM 客户机的显卡的配置为 qxl 型、显存为 65536(即64 MB)、使用在第1号屏幕上

5.6.6、串口和控制台

串口和控制台是非常有用的设备,特别是在调试客户机的内核或遇到客户机宕机的情况下,一般都可以在串口或控制台中查看到一些利于系统管理员分析问题的日志信息

<devices>
    ...
    <serial type='pty'>
        <target port='0'/>
    </serial>
    <console type='pty'>
    	<target type='serial' port='0'/>
    </console>
    ...
</devices>

本示例设置了客户机的编号为 0 的串口(即 /dev/ttyS0),使用宿主机中的伪终端(pty),由于这里没有指定使用宿主机中的哪个虚拟终端,因此 libvirt 会自己选择一个空闲的虚拟终端。当然也可以加上 <source path=‘/dev/pts/1’/> 配置来明确指定使用宿主机中的哪一个虚拟终端。在通常情况下,控制台(console)配置在客户机中的类型为 ‘serial’,此时,如果没有配置串口(serial),则会将控制台的配置复制到串口配置中,如果已经配置了串口,则 libvirt 会忽略控制台的配置项

5.6.7、输入设备

<devices>
    ...
    <input type='mouse' bus='ps2'/>
    <input type='keyboard' bus='ps2'/>
    ...
</devices>

这里的配置会让 QEMU 模拟 PS2 接口的鼠标和键盘

5.6.8、PCI控制器

根据客户机架构的不同,libvirt 默认会为客户机模拟一些必要的 PCI 控制器,而一些 PCI 控制器需要显式地在 XML 配置文件中配置

<controller type='usb' index='0' model='ich9-ehci1'>
    <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x7'/>
</controller>
<controller type='usb' index='0' model='ich9-uhci1'>
    <master startport='0'/>
    <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0' multifunction='on'/>
</controller>
<controller type='usb' index='0' model='ich9-uhci2'>
    <master startport='2'/>
    <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x1'/>
</controller>
<controller type='usb' index='0' model='ich9-uhci3'>
    <master startport='4'/>
    <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x2'/>
</controller>
<controller type='pci' index='0' model='pci-root'/>
<controller type='virtio-serial' index='0'>
    <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
</controller>

这里显式指定了 4个USB 控制器、1个 pci-root 和 1个 virtio-serial 控制器。libvirt 默认还会为客户机分配一些必要的 PCI 设备,如 PCI 主桥(Host bridge)、ISA 桥等

5.7、创建独立设备文件

[root@kvm user]# vim /etc/libvirt/qemu/devices/disk01.xml 
 <disk type='file' device='disk'>
    <driver name='qemu' type='raw' cache='none'/>
    <source file='/img_dir/disk_01.img'/>
    <target dev='sdb' bus='scsi'/>
</disk>

5.8、完整配置示例

<!-- /etc/libvirt/qemu/centos7.xml -->
<domain type='kvm'>
    <name>centos7</name>
    <uuid>2f6260bf-1283-4933-aaef-fa82148537ba</uuid>

    <!-- CPU -->
    <vcpu placement='static'>2</vcpu>
    <features>
        <acpi/>
        <apic/>
    </features>
    <cpu mode='custom' match='exact'>
        <model fallback='allow'>Haswell-noTSX</model>
    </cpu>

    <!-- 内存 -->
    <memory unit='KiB'>2097152</memory>
    <currentMemory unit='KiB'>2097152</currentMemory>

    <!-- 系统类型与启动顺序 -->
    <os>
        <type arch='x86_64' machine='pc'>hvm</type>
        <boot dev='hd'/>
        <boot dev='cdrom'/>
    </os>

    <!-- 网络(NAT) -->
    <devices>
        <interface type='network'>
        <mac address='52:54:00:32:7d:f6'/>
        <source network='default'/>
        <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
        </interface>
    </devices>

    <!-- 存储(硬盘) -->
    <devices>
    <disk type='file' device='disk'>
        <driver name='qemu' type='raw' cache='none'/>
        <source file='/img_dir/centos7.img'/>
        <target dev='sda' bus='scsi'/>
    </disk>
    </devices>

    <!-- 模拟器配置 -->
    <devices>
        <emulator>/usr/libexec/qemu-kvm</emulator>
    </devices>

    <!-- 声卡、显卡配置 -->
    <devices>
        <sound model='ich6'>
            <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
        </sound>
        <video>
            <model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='1'/>
            <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
        </video>
    </devices>

    <!-- 串口和控制台 -->
    <devices>
        <serial type='pty'>
            <target port='0'/>
        </serial>
        <console type='pty'>
            <target type='serial' port='0'/>
        </console>
    </devices>

    <!-- 键盘和鼠标 -->
    <devices>
        <input type='mouse' bus='ps2'/>
        <input type='keyboard' bus='ps2'/>
    </devices>
</domain>