Mastering KVM Virtualization

Mastering KVM Virtualization读书笔记第一章——理解Linux虚拟化

概述

第一章主要包含以下5个内容:

  • Linux虚拟化及基本概念;
  • 为什么选择Linux虚拟化;
  • Hypervisor/VMM;
  • Linux虚拟化在云中向你提供什么;
  • 公有云和私有云;

什么是虚拟化

书中将virtual解释为“硬件环境不是真实的”。在虚拟化中将物理硬件功能复制出来并将他们提供给操作系统(Guest OS)。将这种创建虚拟硬件环境的技术叫做virtualization(虚拟化技术)。运行虚拟化软件(可能是hypervisor或者是VMM)的物理硬件被称为host,安装在虚拟化软件层之上的虚拟机被称为guest。

以上的解释很好地概括了虚拟化的特征,但是除了常规的虚拟PC机这种虚拟化外,虚拟化还有更广的应用和更深的理解。jvm就是一个很好的例子,我们知道Java程序编译成的字节码是无法直接运行在机器上的,字节码运行在jvm上,而jvm正是虚拟化技术的一种应用,jvm抽象出一台可以运行java字节码的虚拟机,从而运行Java编译后的程序。因此只要是能够运行jvm虚拟机的设备就能够使用同一套Java代码,这也正是Java拥有优秀可移植性的原因,同时也是Java程序性能较差的原因。

虚拟化(virtualization)通常容易和模拟/仿真(emulation)搞混(但是如果你用书中对虚拟化的解释来理解,virtualization似乎能包含emulation)。

个人理解,emulation是对硬件寄存器级别的模仿,更多的体现在异构平台转换指令集的操作上,例如在x86平台上运行一个arm设备,可以认为是emulation。对于virtualization更倾向于同一架构平台的虚拟机,对指令集不做翻译,而是通过划分硬件资源(例如将cpu分为多个vCPU等)来提供硬件抽象。因此emulation相对virtualization效率会更差。对于jvm明明是通过翻译字节码工作,却被称为java虚拟机这件事我也感到挺疑惑的。

QEMU本身是一款emulator,但是它通过KVM也可以做到virtualization。关键在于它选择的accelerator是TCG还是KVM。

为什么使用Linux虚拟化

虚拟化在Linux上首次出现是以UML(User-mode Linux)的形式,发展到现在已经有了很多成熟的虚拟化解决方案了,例如:KVM,QEMU,Xen和VirtualBox。

在Linux下许多虚拟化解决方案都是开源的,下面就是巴拉巴拉讲一些开源的好处,略过。

虚拟化的分类

简单地来说,虚拟化就是虚拟一些硬件,例如:网络、存储、应用、I/O存取等,因此虚拟化能够应用在以上任意组件中:

  • SDN(Software-Defined Networking)软件定义网络,即网络虚拟化;
  • SDS(Software-Defined Storage)软件定义存储,存储虚拟化;
  • 应用流、远程桌面都属于应用虚拟化。

SDN我听说过的有一个Open vSwitch,SDS有Ceph。

本书主要聚焦在基于hypervisor的软件虚拟化,即平台虚拟化。在host和guest之间的hypervisor/VMM。

虚拟化的优点

  • 集中服务,节约电力和管理成本。
  • 服务孤立,当我们需要跑两个互相不影响的应用时,一般我们要跑在两台独立的设备上,如果用虚拟化,在一台设备上,我们就能保证服务孤立,内存隔离;
  • 服务快速供应,
  • 灾祸备份,
  • 动态负载均衡,
  • 快速的开发测试环境搭建,
  • 提高系统可靠性和安全性,

略。

操作系统虚拟化/分区

操作系统虚拟化技术运行在同一个物理host上服务并隔离多个不同的工作负载(guest)。请注意,这些工作负载独立地运行在同一种OS上。这使得一个物理服务器可以运行多个隔离的操作系统实例,称之为containers。如果我们叫它基于容器的虚拟化也是没错的。这种虚拟化的优势在于host OS不需要为不同的OS模拟系统调用接口。由于没有提供上述接口,在这种虚拟化类型上不能虚拟其他OS。这是一个常见且很好理解的局限。Solaris containers,FreeBSD jails和Parallel’s OpenVZ都属于此类虚拟化。使用这种方式的时候,所有工作负载都运行在同一个系统上,由内核提供进程隔离和资源管理。虽然所有容器都运行在同一个内核上,但是它们拥有自己的文件系统,进程,内存,设备等等。从另一个角度来说,混杂Windows,Unix和Linux的工作负载在一个物理主机上的就不属于这种虚拟化。这种技术的局限性被性能和效率带来的好处所抵消,因为一个操作系统就提供了所有的虚拟化环境,换而言之,在不同分区间切换讲更为高效。

其实这里讲的就是操作系统虚拟化(容器),近些年比较火爆的是docker,但在此之前其实早就有很多解决方案了。在Linux上将系统资源进行隔离的一个重要组件就是cgroup,在libvirt中也集成了部分操作系统虚拟化工具。

protection rings

在计算机科学中,存在各种保护域/特权环。这是一种用来在发生故障时保护数据和功能,提升容错度,避免恶意操作 ,提升计算机安全的设计方式。

如图所示,rings从内到外编号,特权等级依次递减,ring0是特权等级最高的并且直接与硬件(CPU、内存)交互。内存、I/O端口、CPU指令等资源就是通过这些rings来进行保护的。ring1和ring2通常不怎么使用,通常系统只使用ring0和ring3,即使硬件提供了更多的cpu模式。两个主要的CPU模式就是内核模式和用户模式,从操作系统的角度来看,ring0就是内核模式,ring3则是用户模式。

Linux和Windows操作系统使用内核模式和用户模式,程序在用户模式下无法与外界交互(硬件),除非使用系统调用或者其它帮助,这是由于用户模式下对内存,I/O端口和cpu访问限制导致的。系统内核运行在特权模式下,这意味着它们运行在ring0下。为了执行特定的功能,用户模式下的代码必须执行系统调用。

由于hypervisor/VMM都需要访问内存,cpu和I/O端口,由于只有ring0的代码才能够执行这些操作,因此hypervisor/VMM需要运行在ring0并且在kernel旁边。没有硬件虚拟化支持,运行在ring0的hypervisor/VMM阻碍了guestOS,guestOS只能运行在ring1。虚拟机中的OS同样也希望在察觉不到虚拟化层的情况下访问所有资源,为了达到这个目的,它必须在VMM上跑类似ring0的代码。由于同一时间只能够在ring0上运行一个kernel,guestOS必须运行在其他特权环上,或者经过修改后运行在用户模式。

这导致引入了两种称为完全虚拟化和半虚拟化的虚拟化方法。

全虚拟化

在全虚拟化中,特权指令被模拟以克服由于OS运行在ring1且VMM运行在ring0所产生的限制。全虚拟化基于二进制翻译技术,二进制翻译技术可以陷入或者虚拟某些敏感不可虚拟化的指令。通过二进制翻译技术,一些系统调用被解释并且动态重写。

二进制翻译(binary translation)是通过翻译二进制代码来仿真另一个指令集。这个技术也被用在仿真(emulation)上,比如在QEMU中就可以通过TCG来将arm的指令集动态翻译成x86的指令集。

但是在全虚拟化中,二进制翻译的目标指令集和源指令集为同一指令集,在这里翻译是为了将敏感指令替换成陷入(特权)指令。在全虚拟化中,一般只需要翻译捕捉敏感指令然后进行替换,不含敏感指令的部分可以直接执行。

注意区分敏感指令和特权指令,在x86架构下,特权指令都是敏感指令,但是少部分敏感指令不是特权指令,因此这部分敏感指令需要被替换成特权指令。VMM会捕获(trap)guestOS中发出的特权指令,由VMM处理并返回结果。少部分敏感指令是不会触发trap的,因此需要替换成特权指令。

二进制翻译需要消耗大量的性能,但是通过全虚拟化我们可以使用未被修改过的guestOS。当guest kernel执行特权指令的时候,VMM为它提供针对受保护CPU操作的仿真。

半虚拟化

与全虚拟化相比,半虚拟化需要修改guestOS,以便允许其指令允许在ring0。换句话来说,我们需要修改OS,通过“后端”(超调用)路径来在VMM/hyperviosr和guest之间进行沟通。

半虚拟化和全虚拟化要解决的问题是一样的,都是要考虑如何替换敏感指令,如何执行特权指令。半虚拟化采用的方式是直接修改guestOS,将敏感指令操作替换为对VMM的超调用(hypercall)。

hypercalls陷入到VMM中代替guest kernel执行这个任务,由于guest kernel拥有通过hypercalls直接联系VMM的能力,半虚拟化相较于全虚拟化拥有更优秀的性能表现。

分析全虚拟化和半虚拟化的异同:

同:

  • 全虚拟化和半虚拟化都是为了解决敏感指令的问题;

异:

  • 全虚拟化不修改guestOS,捕获guestOS的敏感指令并翻译成特权指令,CPU在非ring0时执行这些翻译后的特权指令陷入异常,该异常由VMM进行处理,在处理这些异常的时候,VMM替guestOS完成特权指令操作,并返回操作数;
  • 半虚拟化修改guestOS,它直接将敏感指令替换为对VMM的hypercall,这样就减少了捕获、陷入的过程,直接由VMM处理特权指令。

硬件辅助虚拟化

意识到虚拟化的问题,Intel和AMD各自发展出了基于x86扩展的VT-x和AMD-V。硬件辅助虚拟化采用硬件辅助的方式对全虚拟化进行加速。Intel和AMD提供了VT和SVM作为IA-32的指令集扩展。这些扩展允许VMM将guestOS在低特权ring上运行内核模式。硬件辅助虚拟化不仅提供了新的指令集,同样提供了一个新的特权级ring-1。VMM/hypervisor运行在ring-1,guestOS运行在ring0。详细的硬件辅助虚拟化(以KVM为例)实现在书中剩余部分。

硬件辅助虚拟化其实是通过硬件的方式实现了将敏感指令陷入到VMM的工作,从而提高了效率。

hypervisor和VMM

VMM/hypervisor是用来管理控制虚拟机的软件。它负责确保不同的虚拟化任务,例如:提供虚拟硬件、虚拟机生命周期管理、虚拟机迁移、实时分配资源、为虚拟机管理器设置策略等等。同时也要负责有效地控制物理平台资源,例如内存地址翻译和I/O映射。VMM负责为虚拟机分配其所需要的资源,例如进程、内存等。VMM是虚拟化环境的关键组成部分。

几个开源的虚拟化项目

略。