虚拟化是指对资源的逻辑抽象、隔离、再分配、管理的一个过程,通常对虚拟化的理解有广义狭义之分。广义包括平台虚拟化、应用程序虚拟化、存储虚拟化、网络虚拟化、设备虚拟化等等。狭义的虚拟化专门指计算机上模拟运行多个操作系统平台。
虚拟化的目的是通过对硬件资源的抽象和管理,实现资源的高效利用、灵活性、隔离和安全性,从而提供更高效、可靠和可扩展的计算环境。
虚拟化技术和云计算的关系:
KVM全称是Kernel-based Virtual Machine,即基于内核的虚拟机,是采用硬件辅助虚拟化技术的全虚拟化解决方案。对于I/O设备(如硬盘、网卡等),KVM即支持QEMU仿真的全虚,也支持virtio方式的半虚。KVM从诞生开始就定位于基于硬件虚拟化支持的全虚实现,由于其在Linux内核2.6版本后被集成,通过内核加载模式使得Linux内核变成一个事实上的Hypervisor(虚拟机管理器,也叫VMM(Virtual Machine Monitor)),但是硬件管理还是由Linux Kernel来完成。
Hypervisor和VMM:
可以把hypervisor和VMM(virtual machine monitor)理解为同一样东西,它们都是用于监控和控制虚拟机操作系统。在创建虚拟机的过程中,会虚拟出一整套的硬件资源,例如硬盘、内存、CPU、网络设备等,这些工作都是由hypervisor负责,除此之外,它还负责虚拟系统运行过程的资源分配和虚拟机的生命周期管理等。
一个KVM客户机就对应一个Linux进程,每个vCPU对应这个进程下的一个线程,还有单独处理I/O的线程,属于同一个进程组。所以,宿主机上Linux Kernel可以像调度普通Linux进程一样调度KVM虚拟机,这种机制使得Linux Kernel的进程优化和调度功能优化等策略,都能用于KVM虚拟机。比如:通过进程权限限定功能可以限制KVM客户机的权限和优先级等。
由于KVM嵌入Linux内核中,除了硬件辅助虚拟化(如VT-d)的硬件设备能被虚拟机看见外,其他的I/O设备都是QEMU模拟出来的,所以QEMU是KVM天生的好基友。
可以说KVM就是在硬件辅助虚拟化技术之上构建起来的VMM。但并非要求所有硬件虚拟化技术都支持才能运行KVM虚拟化,KVM对硬件最低的依赖是CPU的硬件虚拟化支持(比如:Intel的VT-x技术和AMD的AMD-V技术),而其他的内存和I/O的硬件虚拟化支持,会让整个KVM虚拟化下的性能得到更多的提升。所以在虚拟机部署KVM功能时,首先就是要查看宿主机Host(也就是主机上的虚拟机,这里是在VMware Workstations的虚拟机打开CPU虚拟化功能。
然后在Linux系统中可以通过如下命令确定支持VT-x功能:
如果什么输出都没有,那说明你的系统并没有支持虚拟化的处理 ,不能使用KVM。
"vmx" 是 Intel CPU 的虚拟化技术标识,"svm" 是 AMD CPU 的虚拟化技术标识。
安装KVM及相关的工具:
sudo apt install qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virt-manager
- qemu-kvm
:KVM虚拟化的基本包
- libvirt-daemon-system
:libvirt守护程序,提供API和管理虚拟化功能
- libvirt-clients
:包含用于与libvirt守护程序通信的客户端实用程序
- bridge-utils
:用于创建和管理网络桥接的工具集
- virt-manager
:用于管理虚拟机的图形化工具
确认libvirtd服务已启动并运行:
sudo systemctl start libvirtd
sudo systemctl status libvirtd
#确保在系统启动时自动启动
sudo systemctl enable libvirtd
通过virt-manger(图形化工具)来创建或者管理虚拟机
或者通过virsh(命令行工具)来创建或者管理虚拟机
下面是一些常用的virsh命令:
virsh list
: 列出当前运行的虚拟机virsh start
: 启动指定名称的虚拟机virsh shutdown
: 关闭指定名称的虚拟机virsh reboot
: 重启指定名称的虚拟机virsh create
: 根据指定的XML文件创建虚拟机virsh destroy
: 强制停止指定名称的虚拟机virsh undefine
: 删除指定名称的虚拟机配置virsh console
: 进入指定名称的虚拟机控制台virsh dominfo
: 显示指定名称的虚拟机信息virsh domstate
: 显示指定名称的虚拟机状态接下来分析一下kvm的Makefile :
可以看出kvm的Makefile主要生成三个模块,kvm.o和kvm-intel.o、kvm-amd.o。
资料直通车:Linux内核源码技术学习路线+视频教程内核源码
学习直通车:Linux内核源码内存调优文件系统进程管理设备驱动/网络协议栈
KVM架构
KVM是在硬件虚拟化支持下的全虚拟化技术,所以它能在相应硬件上运行几乎所有的操作系统,KVM虚拟化的核心主要由以下两个模块组成:
1)KVM内核模块,它属于标准Linux内核的一部分,是一个专门提供虚拟化功能的模块,主要负责CPU和内存的虚拟化,包括:客户机的创建、虚拟内存的分配、CPU执行模式的切换、vCPU寄存器的访问、vCPU的执行。
2)QEMU用户态工具,它是一个普通的Linux进程,为客户机提供设备模拟的功能,包括模拟BIOS、PCI/PCIE总线、磁盘、网卡、显卡、声卡、键盘、鼠标等。同时它通过ioctl系统调用与内核态的KVM模块进行交互。
如上图中,在KVM虚拟化架构下,每个客户机就是一个QEMU进程,在一个宿主机上有多少个虚拟机就会有多少个QEMU进程。客户机中的每一个虚拟CPU对应QEMU进程中的一个执行线程,一个宿主机Host中只有一个KVM内核模块,所有虚拟机都与这个内核模块进行交互。
VM内核模块是KVM虚拟化的核心模块,它在内核中由两部分组成:一个是处理器架构无关的部分,用lsmod命令中可以看到,叫作kvm模块;另一个是处理器架构相关的部分,在Intel平台上就是kvm_intel这个内核模块。如下图所示,KVM的主要功能是初始化CPU硬件,打开虚拟化模式,然后将虚拟机运行在虚拟环境下,并对虚拟机的运行提供一定的支持。
以Intel CPU架构服务器为例,KVM打开并初始化硬件以支持虚拟机运行的过程如下:
Step1:在被内核加载的时候,KVM模块会先初始化内部的数据结构。
Step2:做好准备之后,KVM模块检测系统当前的CPU,然后打开CPU控制寄存器CR4中的虚拟化模式开关,并通过执行VMXON指令将宿主操作系统(包括KVM模块本身)置于CPU虚拟化模式中的根模式root operation。
Step3:KVM模块创建特殊设备文件/dev/kvm并等待来自用户空间的命令。
Step4:后续虚拟机的创建和运行,其本质上就是是一个用户空间的QEMU和内核空间的KVM模块相互配合的过程。
这里面的/dev/kvm这个设备比较关键,它可以被当作一个标准的字符设备,用来缓存用户空间与内核空间切换的上下文,也就是ioctl调用上下文,是KVM模块与用户空间QEMU的通信接口。:
QEMU原本就是一个著名的开源虚拟机软件项目,既是一个功能完整的虚拟机监控器,也在QEMU-KVM的软件栈中承担设备模拟的工作。
QEMU最初实现的虚拟机是一个纯软件的实现,也就是我们常说的通过二进制翻译来实现虚拟机的CPU指令模拟,所以性能比较低。但是,其优点是跨平台,甚至可以支持客户机与宿主机并不是同一个架构,比如在x86平台上运行ARM客户机。同时,QEMU能与主流的Hypervisor完美契合,包括:Xen、KVM、Hyper-v,以及VMware各种Hypervisor等,为上述这些Hypervisor提供虚拟化I/O设备。
而QEMU与KVM密不可分的原因,就是我们常说的QEMU-KVM软件协议栈。虚拟机运行期间,QEMU会通过KVM内核模块提供的系统调用ioctl进入内核,由KVM内核模块负责将虚拟机置于处理器的特殊模式下运行。一旦遇到虚拟机进行I/O操作时,KVM内核模块会从上次的系统调用ioctl的出口处返回QEMU,由QEMU来负责解析和模拟这些设备。除此之外,虚拟机的配置和创建,虚拟机运行依赖的虚拟设备,虚拟机运行时的用户操作环境和交互,以及一些针对虚拟机的特殊技术,比如动态迁移,都是由QEMU自己实现的。
总之,KVM 本身不执行任何模拟,需要用户空间应用程序 QEMU
通过 /dev/kvm
接口设置一个客户机虚拟服务器的地址空间,向它提供模拟的 I/O,KVM 模块实现处理器的虚拟化和内存虚拟化。在硬件虚拟化技术的支持下,内核的 KVM 模块与 QEMU 的设备模拟协同工作,构成一套和物理计算机系统完全一致的虚拟化计算机软硬件系统。
监控KVM事件
bcc程序中提供了一个例子用来监控kvm相关事件
源码:
kvm_hypercall.py https://github.com/iovisor/bcc/blob/master/examples/tracing/kvm_hypercall.py
运行结果如下:
这个程序使用了kvm相关的以下几个tracepoint静态跟踪点:
kvm_entry:当虚拟机的vCPU(虚拟中央处理单元)从主机CPU切换到虚拟机CPU并开始执行虚拟指令时,触发kvm_entry跟踪点,vcpu_id用于标识特定的虚拟CPU。
kvm_exit:当虚拟机的vCPU执行完一段虚拟指令并从虚拟机CPU切换回主机CPU时,触发kvm_exit跟踪点,exit_reason表示虚拟cpu推出到主机cpu的具体原因。
kvm_hypercall:用于跟踪虚拟机中的超级调用(hypercall)。当虚拟机的Guest OS需要执行一些更高权限的操作(如:页表的更新、对物理资源的访问等)时,由于自身在非特权域无法完成这些操作,于是便通过超级调用交给Hypervisor来完成这些操作,其中nr代表超级调用号。
kvm_exit中的exit_reason:
上图中的12,18,32分别代表访问任务优先级寄存器(TP),操作系统特定事件,处理器处于AP复位保持状态。
hypercall_nr(超级调用号):
5号超级调用表示请求Hypervisor程序将处于休眠状态的 vCPU 唤醒。