KVM虚拟化架构
KVM是指基于Linux内核的虚拟机(Kernel-base Virtual Machine),增加到Linux内核是Linux发展的一个重要里程碑,这也是第一个整合到Linux主线内核的虚拟化技术。在KVM模型中,每一个虚拟机都是一个由Linux调度程序管理的标准进程,你可以在用户空间启动客户机操作系统,一个普通的Linux进程有两种运行模式:内核和用户,KVM增加了第三种模式:客户模式(有自己的内核和用户模式)。
KVM 与QEMU
KVM仅仅是 Linux 内核的一个模块。管理和创建完整的 KVM 虚拟机,需要更多的辅助工具。
在 Linux 系统中,可以使用 modprobe 系统工具去加载 KVM 模块,如果用 RPM 安装 KVM软件包,系统会在启动时自动加载模块。加载了模块后,才能进一步通过其它工具创建虚拟机。
但仅有 KVM 模块是远远不够的,因为用户无法直接控制内核模块进行操作,因而必须有一个用户空间的工具。关于用户空间的工具,KVM 的开发者选择了已经成型的开源虚拟化软件 QEMU。
QEMU 是一个强大的虚拟化软件,它可以虚拟不同的CPU构架。比如说在x86的CPU上虚拟一个Power的CPU,并利用它编译出可运行在Power上的程序。
KVM 使用了 QEMU 的基于x86的部分,并稍加改造,形成可控制KVM内核模块的用户空间工具QEMU-KVM。
所以Linux发行版中分为kernel部分的KVM内核模块和QEMU-KVM工具。这就是 KVM 和 QEMU 的关系。
KVM虚拟机管理工具
虽然QEMU-KVM工具可以创建和管理KVM虚拟机,但是由于QEMU 工具效率不高,不易于使用,RedHat 为 KVM 开发了更多的辅助工具,比如 libvirt、libguestfs 等。
Libvirt 是一套提供了多种语言接口的 API,为各种虚拟化工具提供一套方便、可靠的编程接口,不仅支持 KVM,而且支持 Xen 等其他虚拟机。
使用 libvirt,只需要通过libvirt提供的函数连接到KVM或Xen宿主机,便可以用同样的命令控制不同的虚拟机了。
Libvirt 不仅提供了 API,还自带一套基于文本的管理虚拟机的命令virsh,可以通过使用 virsh 命令来使用 libvirt 的全部功能。
如果用户希望通过图形用户界面管理KVM,这就是virt-manager工具使用的功能。他是一套用python编写的虚拟机管理图形界面,用户可以通过它直观地操作不同的虚拟机。Virt-manager就是利用 libvirt 的 API 实现的。
宿主机与虚拟机
宿主机是虚拟机的物理基础,虚拟机存在于宿主机中,与宿主机共享使用硬件。宿主机的运行是虚拟机运行的前提与基础。也称宿主机为主机(host)。
虚拟机(Virtual Machine)指通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的完整计算机系统。也称虚拟机为客户机(guest)。
查看硬件是否支持虚拟化
宿主机支持虚拟化技术是使用KVM的前提,因此在开始使用KVM之前需要确认宿主机是否支持虚拟化。
1、查看CPU是否支持虚拟化
通过如下命令查看CPU是否支持虚拟机:
$ egrep 'vmx|svm' /proc/cpuinfo
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology tsc_reliable nonstop_tsc eagerfpu pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xgetbv1 arat umip pku ospke gfni vaes vpclmulqdq movdiri movdir64b md_clear spec_ctrl intel_stibp flush_l1d arch_capabilities
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology tsc_reliable nonstop_tsc eagerfpu pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xgetbv1 arat umip pku ospke gfni vaes vpclmulqdq movdiri movdir64b md_clear spec_ctrl intel_stibp flush_l1d arch_capabilities
# 或者
$ egrep -c '(vmx|svm)' /proc/cpuinfo
8
如果看到有输出结果,即证明cpu支持虚拟化。vmx属于inter处理器,svm属于amd处理器。
2、查看BIOS是否开启虚拟化
使用KVM虚拟化,还需要开启VT(Virtualization Technology),因此需要确认BIOS中是否开启VT,如果没有启用,虚拟机将会变得很慢,无法使用。
安装KVM内核模块以及管理工具
安装 KVM 和相关工具
apt update
apt upgrade
apt install qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virtinst virt-manager -y
启动并启用 Libvirt 服务
sudo systemctl start libvirtd
sudo systemctl enable libvirtd
验证 KVM 安装
virsh --version
加载kvm内核
$ modprobe kvm
$ modprobe kvm-intel
$ lsmod | grep kvm
kvm_intel 372736 0
kvm 1032192 1 kvm_intel
设置网络
仅主机网卡
当安装好kvm,会自动新建一个虚拟网卡,这个虚拟网卡就是仅主机的,这个网卡是无法对外通信的
$ ip a show virbr0
4: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
link/ether 52:54:00:aa:f7:0c brd ff:ff:ff:ff:ff:ff
inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
valid_lft forever preferred_lft forever
如果希望主机的网卡是仅主机的,直接指定这个网卡就可以了
桥接网卡
如果需要桥接网卡,就还需要手动配置
原网卡配置
$ cat /etc/netplan/00-installer-config.yaml
network:
ethernets:
ens32:
dhcp4: no
addresses:
- 10.0.0.129/24
routes:
- to: default
via: 10.0.0.2
nameservers:
addresses:
- 223.6.6.6
search: []
version: 2
新建ens32网卡的桥接网卡
cat /etc/netplan/00-installer-config.yaml
network:
ethernets:
ens32:
dhcp4: no
bridges:
br0:
dhcp4: no
addresses:
- 10.0.0.129/24
gateway4: 10.0.0.2
interfaces:
- ens32
nameservers:
addresses:
- "223.6.6.6"
version: 2
生效
netplan apply
查看网络
ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master br0 state UP group default qlen 1000
link/ether 00:0c:29:18:9b:70 brd ff:ff:ff:ff:ff:ff
altname enp2s0
3: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 2a:47:09:db:0b:cc brd ff:ff:ff:ff:ff:ff
inet 10.0.0.129/24 brd 10.0.0.255 scope global br0
valid_lft forever preferred_lft forever
inet6 fe80::2847:9ff:fedb:bcc/64 scope link
valid_lft forever preferred_lft forever
4: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
link/ether 52:54:00:aa:f7:0c brd ff:ff:ff:ff:ff:ff
inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
valid_lft forever preferred_lft forever
安装虚拟机
新建磁盘文件
qemu-img create -f qcow2 myimage.qcow2 50G
新建一个50G的磁盘,格式为qcow2
上传镜像
$ pwd
/data
$ ll
总计 2055296
drwxr-xr-x 2 root root 4096 Apr 22 11:14 ./
drwxr-xr-x 21 root root 4096 Apr 22 10:42 ../
-rw-r--r-- 1 root root 197408 Apr 22 11:14 myimage.qcow2
-rw-r--r-- 1 libvirt-qemu kvm 2104408064 Mar 25 15:24 ubuntu-22.04.4-live-server-amd64.iso
新建虚拟机
virt-install --name mylinux1 \
--memory 2048 \
--vcpus=2 \
--disk path=/data/myimage.qcow2,size=50,bus=virtio \
--accelerate \
--cdrom /data/ubuntu-22.04.4-live-server-amd64.iso \
--vnc --vnclisten=0.0.0.0 \
--network bridge=br0,model=virtio \
--noautoconsole
此时,可通过vnc viewer连接此安装进程开启的vnc连接端口(默认是5900端口)
查看端口
$ netstat -ntlp | grep qemu
tcp 0 0 0.0.0.0:5900 0.0.0.0:* LISTEN 1875/qemu-system-x8
参数说明
- --name 指定虚拟机名称
- --memory 分配内存大小,单位M。
- --vcpus 分配CPU核心数,最大与实体机CPU核心数相同
- --disk 指定虚拟机镜像,size 指定分配大小单位为G。
- --network 网络类型,此处用的是默认,一般用的都是bridge桥接,这个br0就是在之前宿主机上创建好的一个桥接设备。
- --accelerate 加速参数,在linux系统安装开始就要注意添加提高性能的一些参数,后面就不需要做一些调整了。
- --cdrom 指定安装镜像iso
- --vnc 启用VNC远程管理,一般安装系统都要启用。
- --vncport 指定VNC 监控端口,默认端口为5900,端口不能重复。一般不设置此参数。
- --vnclisten 指定VNC 绑定IP,默认绑定127.0.0.1,这里改为 0.0.0.0。
- --noautoconsole 使用本选项指定不自动试图连接到客户机控制台。默认行为是调用一个VNC客户端显示图形控制台,或者运行 "virsh" "console"命令显示文本控制台。
连接虚拟机
通过VNC Viewer连接宿主机的5900端口
点击连接,就可以连接到虚拟机,看到安装页面
注意
在安装完成系统后,会提示重启,但是,但是,但是,虚拟机并不会重启,而是关机
$ virsh list
Id Name State
--------------------
可以看到,虚拟机已经看不到了
但是可以通过查看所有虚拟机来查看
$ virsh list --all
Id Name State
---------------------------
- mylinux1 shut off
可以看到,是关机的
这个时候,只要开机就好了
$ virsh start mylinux1
Domain 'mylinux1' started
克隆虚拟机
每次安装虚拟机比较浪费时间,KVM提供了虚拟机克隆技术,可以几分钟内克隆出一个新的虚拟机,并不需要安装系统,非常方便迅速。
kvm虚拟机的克隆分为两种情况,
- KVM本机虚拟机直接克隆。
- 通过复制配置文件与磁盘文件复制克隆(适用于异机的静态迁移)。
本机克隆
虚拟机克隆通过 virt-clone
命令来实现
例如,我们的虚拟机是 mylinux1
$ virsh list
Id Name State
--------------------------
4 mylinux1 running
现在我们需要克隆 mylinux1 虚拟机
如果直接克隆,会直接报错
$ virt-clone -o mylinux1 -n mylinux2 -f /data/myimage2.qcow2
ERROR 要克隆的域必须已经关闭。
所以需要先将原虚拟机关机
$ virsh shutdown mylinux1
Domain 'mylinux1' is being shutdown
然后再克隆
$ virt-clone -o mylinux1 -n mylinux2 -f /data/myimage2.qcow2
正在分配 'myimage3.qcow2' 2% [= ] 0 B/s | 1.4 GB --:--:--
正在分配 'myimage2.qcow2' 3% [=- ] 239 MB/s | 1.9 GB 00:03:25
正在分配 'myimage2.qcow2' 5% [== ] 343 MB/s | 2.7 GB 00:02:21
正在分配 'myimage3.qcow2' 6% [==- ] 441 MB/s | 3.5 GB 00:01:48
正在分配 'myimage2.qcow2' 8% [===- ] 542 MB/s | 4.4 GB 00:01:26
正在分配 'myimage3.qcow2' 10% [==== ] 589 MB/s | 5.1 GB 00:01:17
正在分配 'myimage2.qcow2' | 5.1 GB 00:00:06 ...
成功克隆 'mylinux2'。
这个时候就会有两个虚拟机
$ virsh list --all
Id Name State
---------------------------
- mylinux1 shut off
- mylinux2 shut off
那么这个时候就会有个小疑问,那如果两个主机同时启动,vnc的端口会不会冲突呢
这个是不会的,因为我们在创建虚拟机的时候,并没有明确指定vnc的端口,所以如果遇到多个虚拟机需要开启vnc端口,就会在端口5900后延
例如此时同时启动了两个虚拟机,那么端口就是5900和5901
注意: 这里vnc的端口虽然可以平滑克隆,但是虚拟机内部的ip地址是无法平滑克隆的,还是需要手动修改(如果是手动设置的ip地址的话)
虚拟机的迁移
当我们有异机迁移的需求时,该如何来迁移主机呢
KVM虚拟机跨物理机的迁移方式比较简单, 只要拷贝其磁盘文件和xml配置文件,再根据xml来创建域即可
-
需要先确保目标主机满足虚拟机的硬件需求,例如 CPU、内存和磁盘空间
-
在源主机上,使用
virsh
导出虚拟机的 XML 配置文件virsh dumpxml mylinux1 > mylinux1.xml
-
将虚拟机的 XML 配置文件和磁盘文件复制到目标主机
配置文件是刚到出的mylinux1.xml
文件
磁盘文件是创建虚拟机时候新建的磁盘文件myimage.qcow2
-
在目标主机上,确保您已安装了 KVM 和 Libvirt。如果尚未安装,按照安装的步骤安装一下
-
确保虚拟机的磁盘文件路径在 XML 配置文件中正确。如果需要,使用文本编辑器编辑 XML 配置文件,并更新磁盘文件的路径。
<devices> <emulator>/usr/bin/qemu-system-x86_64</emulator> <disk type='file' device='disk'> <driver name='qemu' type='qcow2'/> <source file='/data/myimage.qcow2' index='2'/> <backingStore/> <target dev='vda' bus='virtio'/> <alias name='virtio-disk0'/> <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/> </disk>
将上面的
<source file='/data/myimage.qcow2' index='2'/>
中的file值修改为真是的磁盘文件存放地址 -
加载虚拟机配置生成虚拟机
virsh define mylinux1.xml
-
启动迁移的虚拟机
virsh start mylinux1
KVM虚拟化常用管理命令
1、查看KVM虚拟机配置文件及运行状态
(1) KVM虚拟机默认配置文件位置: /etc/libvirt/qemu/
autostart目录是配置kvm虚拟机开机自启动目录。
(2) virsh命令帮助
$ virsh -help
或直接virsh命令(进入交互模式)
然后再执行子命令。
如下所示。
$ virsh
欢迎使用 virsh,虚拟化的交互式终端。
输入:'help' 来获得命令的帮助信息
'quit' 退出
virsh # help
(3) 查看kvm虚拟机状态
显示虚拟机列表:
virsh # list --all
2、KVM虚拟机开机
启动虚拟机:
virsh # start [name]
3、KVM虚拟机关机或断电
(1) 关机
在安装KVM linux虚拟机必须配置此服务。
#关闭虚拟机:
$ virsh shutdown [name]
(2) 强制关闭电源
$ virsh destroy wintest01
(3)重启虚拟机
重启虚拟机:
$ virsh reboot [name]
(4)查看kvm虚拟机配置文件
$ virsh dumpxml [name]
4、通过配置文件启动虚拟机
$ virsh create /etc/libvirt/qemu/wintest01.xml
5、配置开机自启动虚拟机
$ virsh autostart oeltest01
autostart目录是kvm虚拟机开机自启动目录,可以看到该目录中有KVM配置文件链接。
6、导出KVM虚拟机配置文件
$ virsh dumpxml wintest01 > /etc/libvirt/qemu/wintest02.xml
KVM虚拟机配置文件可以通过这种方式进行备份。
7、添加与删除KVM虚拟机
(1) 删除kvm虚拟机
# 先关机
$ virsh shutdown wintest01
# 再删除
$ virsh undefine wintest01
说明:该命令只是删除wintest01的配置文件,并不删除虚拟磁盘文件。
(2) 重新定义虚拟机配置文件
通过导出备份的配置文件恢复原KVM虚拟机的定义,并重新定义虚拟机。
$ mv /etc/libvirt/qemu/wintest02.xml /etc/libvirt/qemu/wintest01.xml
$ virsh define /etc/libvirt/qemu/wintest01.xml
8、编辑KVM虚拟机配置文件
# 先关机
$ virsh shutdown wintest01
# 在修改
$ virsh edit wintest01
# 启动检查是否生效
$ virsh start wintest01
virsh edit将调用vi命令编辑/etc/libvirt/qemu/wintest01.xml配置文件。也可以直接通过vi命令进行编辑,修改,保存。
可以但不建议直接通过vi编辑。
9、其它virsh命令
(1) 挂起服务器
$ virsh suspend oeltest01
(2) 恢复服务器
$ virsh resume oeltest01
虚拟机快照
新建快照
格式
virsh snapshot-create-as <domain> <snapshot-name>
是要创建快照的虚拟机名称 快照的名称
例如
为虚拟机mylinux1创建快照first-snapshot
$ virsh snapshot-create-as mylinux1 first-snapshot
Domain snapshot first-snapshot created
查看虚拟机的快照
格式
virsh snapshot-list <domain>
是要查看快照的虚拟机名称
例如
$ virsh snapshot-list mylinux1
Name Creation Time State
-------------------------------------------------------
first-snapshot 2024-04-22 15:00:34 +0800 running
还原虚拟机快照
格式
virsh snapshot-revert <domain> <snapshot-name>
是要还原快照的虚拟机名称 快照的名称
例如
virsh snapshot-revert mylinux1 first-snapshot
删除快照
格式
virsh snapshot-delete <domain> <snapshot-name>
是要删除快照的虚拟机名称 快照的名称
例如
$ virsh snapshot-delete mylinux1 snapshot-revert
Domain snapshot snapshot-revert deleted
导出快照的配置
格式
virsh snapshot-dumpxml <domain> <snapshot-name> > <snapshot-xml>
是虚拟机名称 快照的名称 配置文件的名称
这个一般再需要用快照克隆新主机的情况
还需要删除快照配置文件中的 <uuid>
标签,并且将虚拟机的名称修改,然后用这个配置文件创建虚拟机