KVM初识

看完了Xen, 接下来再来接触一下不使用hypervisor的KVM虚拟化技术.

KVM概述

KVM就是Kernel-based Virtualization . 基于内核的虚拟化, 我们之前已经通过使用Xen这种类型一虚拟化来实现虚拟化环境, 通过Dom0虚拟机来实现IO设备模拟交互.

KVM是通过实现一个内核接口来进行虚拟机管理的, KVM作为一个内核模块, 当我们装载了之后整个Linux内核就会变成一个HyperVisor了. 因此当创建了一个虚拟机之后, 在操作系统中被抽象成了一个进程, 我们甚至可以通过ps来看到他们, 那关闭一个虚拟机咋做? 很简单, 直接kill就完事了. 在KVM出现之后, 由于他和内核的相性使得Linux直接抛弃了原先的Xen, 实装了KVM到内核模块中, 至于一些支持Xen和KVM的管理工具, 就被砍去了对Xen的部分功能.

对于KVM而言, 硬件辅助虚拟技术(HVM)也是必要的, 因此我们需要在虚拟机测试的环境下开启硬件虚拟化. KVM在我们的/dev目录下有一个专门的文件, /dev/kvm. 当我们想要创建虚拟机的时候, 就向这个文件发送请求即可, 他会和我们的KVM内核模块打交道. 现在来想象一下, 在装载了KVM并且新建一个虚拟机之后, 假设这还是一个Linux虚拟机, 那么他也会有自己的用户空间和内核空间, 这就比较麻烦, 我们知道有内核模式和用户模式, 此时我们引入了一个新的模式叫做宾客模式(guest mode). 也就是这个虚拟机对应的用户空间的模式名.

由此, 在我们载入KVM模块之后, 我们的系统就会有三种运行模式了:

  • 内核模式: 虚拟机的内核模式
  • 用户模式: 代表GuestOS执行I/O类操作, host的用户模式
  • 来宾模式: GuestOS的非I/O操作, 该模式可以说成是虚拟机的用户模式

此时我们的Host的内核就扮演成Hypervisor的角色了.

除了上面提到的/dev/kvm, 另外一个重要的KVM组件就是我们之前也见过的qemu进程. 先来说说/dev/kvm. 我们知道这个东西是KVM的一个入口, 作为一个字符设备来存在, 可以通过ioctl()系统调用来完成VM创建, 启动, 分配内存, 读写VCPU的寄存器等等. 而qemu, 工作在用户空间, 主要用于实现模拟PC机的IO设备.

KVM可以使用Linux的大内存页(Huge Page), 也支持将分配给虚拟机的内存进行swap交换. 另外, KVM还可以使用KSM(Kernel Same-page Merging), 合并相同的内存页.

接着我们来说说KVM的设备驱动, 首先是IO设备的完全虚拟化, 很简单了这就是模拟硬件. 而对于IO设备的半虚拟化, 我们需要在GuestOS中安装驱动, 叫做virtio.

KVM优点很多, 但也有一些局限性, 例如KVM的过载使用(overcommit), 还有虚拟机的时钟, 由于VCPU的存在就会导致时间同步出错.

KVM的工具栈

除了上面说的Qemu, 另外一组KVM的工具栈就是使用libvirt的virsh. 在qemu中我们主要使用qemu-kvm和qemu-img这两个工具. 而libvirt支持在GUI和CLI两种模式下的, 使用到的工具也不尽相同. 我们从Qemu开始.

Qemu

我们QEMU主要提供一下几个部分:

  • 处理器模拟器
  • 仿真IO设备
  • 关联模拟设备到真实设备
  • 调试器
  • 与模拟器交互的用户接口