现在使用的计算机都离不开冯诺依曼体系结构,如图所示,有输入设备、输出设备、存储器、cpu 这就算是完整的计算机硬件环境了(当然还需要网卡、显卡等等)。虚拟化技术就是在一台机器上模拟出独立的 cpu、存储器等使得同一台主机能虚拟为多台主机或者多台主机能虚拟为一台主机。
虚拟化使用软件的方法重新定义划分 IT 资源,可以实现 IT 资源的动态分配、灵活调度、跨域共享,提高 IT 资源利用率,使 IT 资源能够真正成为社会基础设施,服务于各行各业中灵活多变的应用需求。
半虚拟化、全虚拟化、寄居虚拟化、裸金属虚拟化、硬件虚拟化、软件虚拟化、CPU、内存、磁盘、网络虚拟化
最理想的虚拟化的两个目标如下:
- 客户机完全不知道自己运行在虚拟化环境中,还以为自己运行在原生环境里。
- 完全不需要 VMM 介入客户机的运行过程。
纯软件的虚拟化可以做到第一个目标,但性能不是很好,而且软件设计的复杂度大大增加。那么如果放弃第一个目标呢?让客户机意识到自己是运行在虚拟化环境里,并做相应修改以配合 VMM,这就是半虚拟化(Para-Virtualization)。
一方面,可以提升性能和简化 VMM 软件复杂度;另一方面,也不需要太依赖硬件虚拟化的支持,从而使得其软件设计(至少是 VMM 这一侧)可以跨平台且是优雅的。“本质上,准虚拟化弱化了对虚拟机特殊指令的被动截获要求,将其转化成客户机操作系统的主动通知。但是,准虚拟化需要修改客户机操作系统的源代码来实现主动通知。” 典型的半虚拟化技术就是 virtio,使用 virtio 需要在宿主机 / VMM 和客户机里都相应地装上驱动。
与半虚拟化相反的,全虚拟化(Full Virtualization)坚持第一个理想化目标:客户机的操作系统完全不需要改动。敏感指令在操作系统和硬件之间被 VMM 捕捉处理,客户操作系统无须修改,所有软件都能在虚拟机中运行。因此,全虚拟化需要模拟出完整的、和物理平台一模一样的平台给客户机,这在达到了第一个目标的同时也增加了虚拟化层(VMM)的复杂度。
性能上,2005 年硬件虚拟化兴起之前,软件实现的全虚拟化完败于 VMM 和客户机操作系统协同运作的半虚拟化,这种情况一直延续到 2006 年。之后以 Intel VT-x、VT-d 为代表的硬件虚拟化技术的兴起,让由硬件虚拟化辅助的全虚拟化全面超过了半虚拟化。但是,以 virtio 为代表的半虚拟化技术也一直在演进发展,性能上只是略逊于全虚拟化,加之其较少的平台依赖性,依然受到广泛的欢迎。
最底层是物理硬件,物理硬件之上是主机的操作系统,操作系统之上是 VMM(virtual machine monitor, 虚拟机管理层),再往上就是客户的虚拟户了。
在这种技术里面,虚拟机对各种物理设备(cpu、内存、硬盘等)的调用,都是通过 VMM 层和宿主机的操作系统一起协调才完成的。VMware 和 VirtualBox 都是基于这种方式实现的。
裸机虚拟化指的是,直接将 VMM 安装在硬件设备与物理硬件之间。VMM 在这种模式下又叫做 Hypervisor, 虚拟机有指令要执行时, Hypervisor 会接管该指令,模拟相应的操作。
Hypervisor 是一种在虚拟环境中的 “元” 操作系统。他们可以访问服务器上包括磁盘和内存在内的所有物理设备。 Hypervisor 不但协调着这些硬件资源的访问,也同时在各个虚拟机之间施加防护。当服务器启动并执行 Hypervisor 时,它会加载所有虚拟机客户端的操作系统同时会分配给每一台虚拟机适量的内存,CPU,网络和磁盘。
硬件虚拟化技术就是指计算机硬件本身提供能力让客户机指令独立执行,而不需要(严格来说是不完全需要)VMM 截获重定向。
以 x86 架构为例,它提供一个略微受限制的硬件运行环境供客户机运行(non-root mode),在绝大多数情况下,客户机在此受限环境中运行与原生系统在非虚拟化环境中运行没有什么两样,不需要像软件虚拟化那样每条指令都先翻译再执行,而 VMM 运行在 root mode,拥有完整的硬件访问控制权限。仅仅在少数必要的时候,某些客户机指令的运行才需要被 VMM 截获并做相应处理,之后客户机返回并继续在 non-root mode 中运行。可以想见,硬件虚拟化技术的性能接近于原生系统,并且,极大地简化了 VMM 的软件设计架构。
软件虚拟化,顾名思义,就是通过软件模拟来实现 VMM 层,通过纯软件的环境来模拟执行客户机里的指令。最纯粹的软件虚拟化实现当属 QEMU。在没有启用硬件虚拟化辅助的时候,它通过软件的二进制翻译仿真出目标平台呈现给客户机,客户机的每一条目标平台指令都会被 QEMU 截取,并翻译成宿主机平台的指令,然后交给实际的物理平台执行。由于每一条都需要这么操作一下,其虚拟化性能是比较差的,同时其软件复杂度也大大增加。但好处是可以呈现各种平台给客户机,只要其二进制翻译支持。
详细内容可参考:https://www.pianshen.com/article/701760589/
cpu 虚拟化指的就是把物理的 cpu 虚拟为多个虚拟 cpu,从而实现一个 cpu 能被多台虚拟机共用,但是却相互隔离的场景。cpu 的运转是以时间为单位的,cpu 虚拟化要解决的问题主要是隔离和调度问题,隔离指的是让不同的虚拟机之间能够相互独立的执行命令,调度指的是 VMM 决定 cpu 当前在哪台虚拟机上执行。
由于 x86 体系设计的 cpu 在虚拟化上具有一定的缺陷,所以我们有两种方法来实现 cpu 的虚拟化。其一是采用完全虚拟化的方式,利用动态指令转换或者硬件辅助来帮助实现 cpu 的虚拟化;其二是采用半虚拟化得方式,在客户的操作系统内核上进行一定的更改使得操作系统自己明白自己是虚拟机的角色,能够在 VMM 的管理下尽可能的访问硬件。(硬件辅助虚拟化 软件辅助虚拟化)
影子页表:https://www.51cto.com/article/686032.html
扩展表 EPT:https://www.pianshen.com/article/701760589/
内存提出的原因:
首先,内存存在的原因是 cpu 运转速度极快,超过了磁盘的读取速度,如果 cpu 直接读取硬盘的话,大部分的时间 cpu 都在等待。同时,程序访问又拥有局部性原理(80% 的访问都在访问数据中 20% 的数据),于是乎就有牛人想到能不能用一小块儿读取速率快的存储设备来存放经常被读取的数据,这样 cpu 处理数据的速度就能和存储器读取设备的速度相匹配。系统性能达到最大化。
虚拟内存:
早期的计算机内存,只有物理内存,而且空间是极其有限的,每个应用或进程在使用内存时都得小心翼翼,不能覆盖别的进程的内存区。
为了避免这些问题,就提出了虚拟内存的概念,其抽象了物理内存,相当于对物理内存进行了虚拟化,保证每个进程都被赋予一块连续的,超大的(根据系统结构来定,32 位系统寻址空间为 2^32,64 位系统为 2^64)虚拟内存空间,进程可以毫无顾忌地使用内存,不用担心申请内存会和别的进程冲突,因为底层有机制帮忙处理这种冲突,能够将虚拟地址根据一个页表映射成相应的物理地址。
这种机制正是虚拟化软件做的事,也就是 MMU 内存管理单元。
假设我们设定的虚拟内存是 4G, 虚拟内存就是给系统当中的每一个进程分配 4G 的虚拟地址,这样每个进程都感觉自己是独立的使用一块儿内存,具有良好的隔离性,同时,每个进程都是从 0 的虚拟地址开始的,这样就更有助于管理进程。但程序要运行,必须要运行在真实的内存上,所以会建立一种映射机制来帮助实现虚拟地址到物理地址之间的映射。
通过虚拟内存的方式实现了进程之间的地址隔离。(32 位的 CPU 的寻址空间是 4G , 所以虚拟内存的最大值为 4G , 而 windows 操作系统把这 4G 分成 2 部分, 即 2G 的用户空间和 2G 的系统空间, 系统空间是各个进程所共享的, 他存放的是操作系统及一些内核对象等, 而用户空间是分配给各个进程使用的, 用户空间包括用: 程序代码和数据, 堆, 共享库, 栈。)
内存的虚拟化:
内存的虚拟化指的是把物理内存包装成若干虚拟内存来使用,把物理内存抽象出来,给每一台虚拟机都分配一个连续的内存空间。
内存软件虚拟化的目标就是要将虚拟机的虚拟地址(Guest Virtual Address, GVA)转化为 Host 的物理地址(Host Physical Address, HPA),中间要经过虚拟机的物理地址(Guest Physical Address, GPA)和 Host 虚拟地址(Host Virtual Address)的转化,即:GVA -> GPA -> HVA -> HPA
硬盘虚拟化相对简单一些,拿 VMvare 来举例,在 VMvare 当中,会使用物理硬盘上的一个文件来当做虚拟机当中的一个硬盘,虚拟机通过调用相关进程(如 VMvare 进程)访问相关的宿主机的文件系统,再通过文件系统调用 windows 内核,再调用驱动,然后在磁盘上进行读写。
网络虚拟化是让一个物理网络能够支持多个逻辑网络,虚拟化保留了网络设计中原有的层次结构、数据通道和所能提供的服务,使得最终用户的体验和独享物理网络一样,同时网络虚拟化技术还可以高效的利用网络资源如空间、能源、设备容量等。网络虚拟化的目的,是要节省物理主机的网卡设备资源。
传统网络架构:
在传统网络环境中,一台物理主机包含一个或多个网卡(NIC),要实现与其他物理主机之间的通信,需要通过自身的 NIC 连接到外部的网络设施
这种架构下,为了对应用进行隔离,往往是将一个应用部署在一台物理设备上,这样会存在两个问题
- 是某些应用大部分情况可能处于空闲状态
- 是当应用增多的时候,只能通过增加物理设备来解决扩展性问题。不管怎么样,这种架构都会对物理资源造成极大的浪费。
虚拟化网络架构:
借助虚拟化技术对一台物理资源进行抽象,将一张物理网卡虚拟成多张虚拟网卡(vNIC),通过虚拟机来隔离不同的应用。
这样对于上面的问题
- 可以利用虚拟化层 Hypervisor 的调度技术,将资源从空闲的应用上调度到繁忙的应用上,达到资源的合理利用
- 可以根据物理设备的资源使用情况进行横向扩容,除非设备资源已经用尽,否则没有必要新增设备。这种架构如下所示。
虚拟机与虚拟机之间的通信,由虚拟交换机完成,虚拟网卡和虚拟交换机之间的链路也是虚拟的链路,整个主机内部构成了一个虚拟的网络,如果虚拟机之间涉及到三层的网络包转发,则又由另外一个角色——虚拟路由器来完成。
一般,这一整套虚拟网络的模块都可以独立出去,由第三方来完成,如其中比较出名的一个解决方案就是 Open vSwitch(OVS)。
OVS 的优势在于它基于 SDN 的设计原则,方便虚拟机集群的控制与管理,另外就是它分布式的特性,可以「透明」地实现跨主机之间的虚拟机通信
总结:网络虚拟化主要解决的是虚拟机构成的网络通信问题,完成的是各种网络设备的虚拟化,如网卡、交换设备、路由设备等。
KVM 为完全虚拟化技术,依赖在操作系统上,需要在操作系统上运行,不能直接在物理机上运行,这种虚拟化必须要求 cpu 支持虚拟化功能,即虚拟化模块内置在 cpu 中,因此 kvm 就不用将 cpu 和内存全部模拟出来,直接调用物理机 cpu 和内存只需对它们执行分配操作,使得虚拟机的性能大大提升,其性能与物理机基本相当,kvm 模块是内置在 linux 系统中的,是系统自带的,无需再安装。
半虚拟化,要求客户机系统的内核要知道自己是在虚拟化环境中运行,所以客户机系统架构要和宿主机或物理机系统架构相同,即需要支持客户机系统内核的修改;支持内核修改的系统必然是开源系统,而闭源系统就不支持内核修改,例如微软、苹果的操作系统都不开源,不支持 xen 半虚拟化技术 ,这是 XEN 的一大缺陷,3.0 版本之后也支持完全虚拟化。
由于现在大多数 CPU 都内置虚拟化功能,所以基本都支持 KVM 虚拟化技术;而 XEN 虚拟化技术必须得是开源的操作系统、需要修改客户机系统内核、要保持客户机系统架构和宿主机系统架构一致,这是 XEN 的一大致命缺陷,避免不了逐渐被 KVM 替代,不过 3.0 版本之后 XEN 也支持完全虚拟化,提高了兼容性,由于 KVM 的火热依然挡不住被 KVM 替代。
虚拟化 VNWARE-esxi 是一个独立的操作系统,直接运行在物理机上,不依赖操作系统,esxi 有自带的服务端管理服务器,可创建虚拟机,上传镜像文件,此管理服务器不支持虚拟机的移动;但将 vsphere-server 安装在 window-server2008 上可以实现远程服务端管理虚拟机,支持将虚拟机的移动到另一台物理机上,同样支持虚拟机的创建和 iso 镜像文件的上传。
- raw:指定多大空间就创建多大空间,相当于一个占用物理空间的文件,可以直接挂载使用,数据的保存在磁道上是顺序保存,所以其性能是最好的,但占用的空间是最大的,不利于虚拟机的迁移,KVM 和 XEN 默认此磁盘格式。
- qcow2:主流的虚拟化镜像格式,可以在镜像上做多个快照,数据的保存在磁道上是随机的,性能接近 RAW 磁盘格式,磁盘占用更小的存储空间,磁盘占用物理空间的大小是随着存入磁盘的数据的增加而增大,虚拟机的迁移比 RAW 格式更快捷。
- vmdk:kvm 和 XEN 等虚拟技术上用的不多,但在 vmware-esxi 上此镜像格式性能还是相当稳定,比较出色。
- KVM /QEMU /LIBVIRTD
- KVM 是 linux 内核的模块,它需要 CPU 的支持,采用硬件辅助虚拟化技术 Intel-VT,AMD-V,内存的相关如 Intel 的 EPT 和 AMD 的 RVI 技术
- QEMU 是一个虚拟化的仿真工具,通过 ioctl 与内核 kvm 交互完成对硬件的虚拟化支持
- Libvirt 是一个对虚拟化管理的接口和工具,提供用户端程序 virsh ,virt-install, virt-manager, virt-view 与用户交互
- qemu-kvm
- 为 kvm 提供底层仿真支持
- libvirt-daemon
- libvirtd 守护进程,管理虚拟机
- libvirt-client
- 用户端软件,提供客户端管理命令
- libvirt-daemon-driver-qemu
- libvirtd 连接 qemu 的驱动
- 内核虚拟化模块(KVM)
- 系统设备仿真(QEMU)
- 虚拟机管理程序(LIBVIRT)
- 一个 XML 文件(虚拟机配置声明文件)
- 位置 /etc/libvirt/qemu/
- 一个磁盘镜像文件(虚拟机的硬盘)
- 位置 /var/lib/libvirt/images/
- libvirtd 为管理虚拟机提供服务接口
- 调用 dnsmasq 提供 DNS、DHCP 等功能
- 建立 virbr0 虚拟网络(192.168.122.0/24)
- systemctl restart libvirtd (装完包后启动服务)
- 提供管理各虚拟机的命令接口
- 支持交互模式,查看 / 创建 / 停止 / 关闭.. ..
- 格式:virsh 控制指令 [虚拟机名称] [参数]
- 查看 KVM 节点(服务器)信息
- virsh nodeinfo
- 列出虚拟机
- virsh list [--all]
- 列出虚拟网络
- virsh net-list [--all]
- 查看指定虚拟机的信息
- virsh dominfo 虚拟机名称
- 运行 | 重启 | 关闭挃定的虚拟机
- virsh start|reboot|shutdown 虚拟机名称
- 强制关闭指定的虚拟机
- virsh destroy 虚拟机名称
- 将指定的虚拟机设为开机自动运行
- virsh autostart[--disable] 虚拟机名称
导出虚拟机
- xml 配置文件
- 定义了一个虚拟机的名称、UUID、CPU、内存、虚拟磁盘、网卡等各种参数设置
- 默认位于 / etc/libvirt/qemu / 虚拟机名. xml
- 导出 xml 配置文件
- 查看:virshdumpxml 虚拟机名
- 备份:virshdumpxml 虚拟机名 > 虚拟机名. xml
编辑虚拟机设置
- 对虚拟机的配置进行调整
- 编辑:virsh edit 虚拟机名
- 若修改 name、uuid、disk、mac,可自动保存为新虚拟机配置
导入虚拟机
- 根据修改后的独立 xml 文件定义新虚拟机
- virsh define XML 描述文件
删除虚拟机
- 必要时可去除多余的 xml 配置
- 比如虚拟机改名的情况
- 避克出现多个虚拟机的磁盘或 MAC 地址冲突
- virsh undefine 虚拟机名
常用镜像盘类型
- 虚拟机的磁盘镜像文件格式
特点类型 |
RAW |
QCOW2 |
KVM 默认 |
否 |
是 |
I/O 效率 |
高 |
较高 |
占用空间 |
大 |
小 |
压缩 |
不支持 |
支持 |
后端盘复用 |
不支持 |
支持 |
快照 |
不支持 |
支持 |
创建虚拟机磁盘镜像
- 创建新的镜像盘文件
- qemu-img create -f 格式磁盘路径大小
- 查询镜像盘文件的信息
- qemu-img info 磁盘路径
创建 / 还原 / 删除快照
- 快照的作用
- 在虚拟机磁盘镜像内记录不同时间点的状态数据备份
- 必要时可将虚拟机恢复到指定的快照
- 基本用法
- qemu-img snapshot -c 快照名 qcow2 磁盘
- qemu-img snapshot -l qcow2 磁盘
- qemu-img snapshot -a 快照名 qcow2 磁盘
- qemu-img snapshot -d 快照名 qcow2 磁盘
重点!!!
一台 KVM 虚拟机的组成
- 一台 KVM 虚拟机的组成
- xml 配置文件:定义虚拟机的名称、UUID、CPU、内存、虚拟磁盘、网卡等各种参数设置
- 磁盘镜像文件:保存虚拟机的操作系统及文档数据,镜像路径取决于 xml 配置文件中的定义
基本思路
- 准备一台模板虚拟机(镜像磁盘 + xml 配置文件)
- 基于磁盘复用技术快建新虚拟机的磁盘
- 通过调整模板机的配置快建新虚拟机的 xml 配置文件
- 导入新虚拟机
- Copy On Write,写时复制
- 直接映射原始盘的数据内容
- 当原始盘的旧数据有修改时,在修改之前自劢将旧数据存入前端盘
- 对前端盘的修改丌回写到原始盘
- 预装软件 / 系统优化 / 关闭 SELinux 等
- 生产环境可以标记 /.unconfigured,方便新虚拟机的配置(相当于出厂设置,提示用户初始化)
- 备份好模板磁盘、xml 配置文件
- 删除模板机(undefine)
- qemu-img 通过 - b 选项复用挃定后端盘
- qemu-imgcreate -f qcow2 -b 后端盘前端盘
- 拷贝模板机的 xml 配置
- 挄照需要修改,并据此定义新虚拟机
- 正常运行快建的新虚拟机
- 检查已有装好的操作系统,登入后不模板机一样
- 用户自行修改主机名 / IP 地址等参数
- 扩展:使用 guestmount 工具
- 支持离线挂载 raw、qcow2 格式虚拟机磁盘
- 可以在虚拟机关机的情况下,直接修改磁盘中的文档
- 方便对虚拟机定制、修复、脚本维护
- 基本用法
- guestmount -a 虚拟机磁盘路径 -i / 挂载点