云原生运维学习笔记:揭开虚拟化的硬核面纱,从底层架构到KVM实战
第一阶段的Linux基础和云计算概览算是告一段落了。说实话,昨天刚看完那几份PPT的时候,我感觉脑子里塞满了各种名词:IaaS、VLAN、SAN、RAID......当时觉得云计算的底层真的是又碎又多。但今天进入虚拟化技术的课程,尤其是拿着《1021实际学习内容》这份文档仔细啃完之后,我突然有了一种"打通任督二脉"的感觉。
之前学服务器硬件、学操作系统,都是把一台物理机当成一个整体来看。而虚拟化技术,硬生生地把物理机的CPU、内存、I/O这些硬件资源拆成了"乐高积木",然后重新拼装成一个个虚拟机。这个过程背后的原理,尤其是CPU和内存的虚拟化,真的极其硬核。这篇博客我就抛开那些走马观花的泛泛而谈,紧扣我们今天实际学习的核心内容,把虚拟化的底层逻辑掰开揉碎了记录一下,顺便附上在Linux下用KVM/Libvirt动手实操的命令。
一、 虚拟化到底是个啥?(概念重塑)
在今天的《1021实际学习内容》里,开篇就给虚拟化定了调子:解除了物理硬件和操作系统之间的紧耦合关系。
以前一台服务器装一个Windows或Linux,应用就跑在这上面。现在我们在中间塞了一个叫Hypervisor(虚拟机监控器,VMM)的东西。它把底层的物理资源抽象成一个共享资源池,然后在上层虚拟出多台"Guest Machine"(虚拟机)。
这里面有几个必须刻在DNA里的概念:
- Host OS / Host Machine:也就是宿主机,真实跑着的物理服务器和上面的操作系统。
- Guest OS:跑在虚拟机里面的操作系统。
- Hypervisor:核心大佬,虚拟化软件层。
为什么企业都要用虚拟化?文档里总结了四大特点,我觉得拿来做备忘录特别合适:
- 分区:一台物理机同时跑多台虚拟机,每台虚拟机都觉得自己独占了一台服务器。
- 隔离:虚拟机之间互不干扰。A虚拟机中毒了,B虚拟机该干嘛干嘛,资源也能通过控制确保不被某台虚拟机"吃独食"。
- 封装:整台虚拟机(硬件配置、BIOS、内存状态、磁盘状态)就相当于几个文件。拷贝文件就等于拷贝了整台服务器。
- 相对于硬件独立:虚拟机跑在虚拟化层上,底层物理机是IBM、Dell还是HP根本无所谓,直接无缝迁移。
虚拟化也分派系:全虚拟化 (不用改Guest OS,但性能有开销)、半虚拟化 (需要改Guest OS配合,性能好但兼容差)、硬件辅助虚拟化(靠CPU硬件支持,现在的绝对主流)。
二、 硬核拆解:CPU虚拟化到底难在哪?
这是今天最烧脑,也是最让我拍大腿的一节。
1. x86架构的"先天缺陷"
我们先得明白CPU的分级保护域。在x86架构下,CPU被分成了4个环:Ring 0、Ring 1、Ring 2、Ring 3。Ring 0权限最高,可以直接操作硬件(内核态);Ring 3权限最低(用户态)。
而在指令集上,分为普通指令 (Ring 3执行)和特权指令 (Ring 0执行)。在ARM(RISC精简指令集)架构下,所有敏感指令都是特权指令,这好办。但在x86(CISC复杂指令集)架构下,偏偏有19条敏感的非特权指令!
这意味着什么?当操作系统(本来该在Ring 0)被虚拟化放到Ring 1去跑时,它一旦执行这19条指令,系统不会触发异常陷入Hypervisor,而是直接在物理硬件上执行了,这就导致了虚拟化环境的崩溃。这就是x86架构最初不适合虚拟化的根本原因。
2. 解决方案的演进路线
为了解决这19条"刺头"指令,技术演进经历了三个阶段:
① 二进制翻译(BT - Binary Translation)
既然执行会出问题,那就在执行前检查一遍。VMM在Guest OS指令段执行前,进行整段翻译。把里面那些敏感的、非特权的指令,全部替换成能够触发陷入模拟的指令。特权指令被陷入到VMM后,VMM进行模拟,然后再返回给Guest OS。
- 优点:Guest OS完全无感知,兼容性好。
- 缺点:负载大、频繁翻译时性能极差(早期VMware就是这个路子)。
② 半虚拟化(Para-Virtualization)
直接改代码!在Guest OS里面集成半虚拟化代码,让它能识别Hypervisor。Hypervisor提供Hypercall接口来满足Guest OS的内存管理、中断等内核操作。
- 优点:性能极其接近物理机。
- 缺点:没法跑没修改过的Windows系统,兼容性差(早期Xen走的路)。
③ 硬件辅助虚拟化(VMX模式)
Intel和AMD终于在硬件层面出手了。引入了VMX模式(Virtual Machine eXtension) ,把CPU直接分成了两个大区:VMX Root模式 (给VMM用)和VMX Non-Root模式 (给Guest OS用)。
当Guest OS在Non-Root模式执行那19条敏感指令时,硬件直接捕获,产生一个VM-Exit (虚拟机退出),切换到Root模式让VMM处理。处理完再通过VM-Entry 切回Guest OS。
现在Intel的VT-x和AMD的AMD-V都是这个机制,真正的性能与兼容性兼得。
三、 内存虚拟化:从GVA到HPA的"三段位移"
CPU搞定了,内存呢?以前物理机上,内存都是从地址0开始的连续空间。但虚拟化环境下,多台虚拟机怎么可能都独占从0开始的内存?
所以这里引入了三个地址概念(重点划线):
- GVA (Guest Virtual Address):客户机虚拟地址(Guest OS里应用看到的地址)。
- GPA (Guest Physical Address):客户机物理地址(Guest OS以为的物理地址)。
- HPA (Host Physical Address):宿主机物理地址(真正物理内存条上的地址)。
内存虚拟化的核心,就是地址转换。
转换机制的演进
最传统的做法是影子页表(Shadow Page Table)。由于宿主机MMU不能直接装客户机的页表,VMM得在底层维护一张表,把GVA直接映射到HPA。Guest OS一改页表,VMM就得跟着把影子页表也改一遍,极其消耗性能。
后来,Intel搞出了EPT(Extended Page Tables,扩展页表) ,AMD也有对应的NPT。
CR3寄存器把GVA转为GPA(由Guest OS维护),然后硬件自动查询EPT,把GPA转为HPA(由VMM维护)。这两次转换在硬件底层一步到位,翻译效率极高,彻底解放了VMM的CPU压力。
四、 KVM与QEMU:内核与用户的"双剑合璧"
了解了原理,我们看看实际的Linux虚拟化方案。
KVM (Kernel-based Virtual Machine) 本质上只是Linux内核的一个模块(kvm.ko)。它主要负责CPU和内存的虚拟化 。
但是光有KVM不行,它不具备I/O设备模拟的能力。所以,QEMU(一个纯软件实现的开源模拟软件)登场了。
KVM + QEMU 怎么配合?
- KVM 运行在内核空间,管CPU和内存。
- QEMU 运行在用户空间,负责硬件I/O的虚拟化模拟。
- 两者通过
/dev/kvm文件进行交互。
在KVM中,虚拟机其实就是一个普通的Linux进程(叫qemu-kvm进程),由Linux内核的CPU调度器来调度它运行!
实战:使用Libvirt命令行管理虚拟机
虽然我们平时在桌面端用 virt-manager 点点鼠标就能建虚拟机,但在没有图形界面的服务器上,还是得靠命令行。这里用到的是 Libvirt。
Libvirt 是一套通用且稳定的API库(底层是C语言写的),它可以同时管理KVM、Xen、VMware等。这里面有三个核心概念:
- Node(节点):物理机。
- Hypervisor(虚拟机监控器):比如KVM。
- Domain(域):也就是一台虚拟机实例。
下面是我在CentOS 7环境下实操的几个 virsh 命令(属于libvirt原生命令行管理工具,功能最全):
1. 查看当前节点上的所有虚拟机
bash
[root@server ~]# virsh list --all
Id 名称 状态
----------------------------------------------------
1 centos7-vm running
- test-vm 关闭
2. 启动、关闭、重启虚拟机
bash
# 启动一台叫test-vm的虚拟机
[root@server ~]# virsh start test-vm
域 test-vm 已启动
# 正常关闭(相当于在系统里执行shutdown命令)
[root@server ~]# virsh shutdown test-vm
域 test-vm 被关闭
# 强制关闭(拔电源)
[root@server ~]# virsh destroy test-vm
域 test-vm 被删除(仅关闭电源,不删配置文件)
# 重启
[root@server ~]# virsh reboot test-vm
域 test-vm 正在重新启动
3. 查看虚拟机的XML配置详情(核心)
Libvirt 把虚拟机的所有配置(CPU、内存、磁盘、网卡)都保存为一个XML文件。
bash
[root@server ~]# virsh dumpxml centos7-vm | head -n 20
<domain type='kvm' id='1'>
<name>centos7-vm</name>
<uuid>8b1f1e63-17a1-4314-8915-36b3e2331281</uuid>
<memory unit='KiB'>2097152</memory>
<currentMemory unit='KiB'>2097152</currentMemory>
<vcpu placement='static'>2</vcpu>
<os>
<type arch='x86_64' machine='pc-i440fx-rhel7.6.0'>hvm</type>
<boot dev='hd'/>
</os>
... (省略部分输出)
你看,<memory> 和 <vcpu> 就是内存和CPU配置。如果想修改CPU核数,可以直接编辑XML:
bash
[root@server ~]# virsh edit centos7-vm
# 会调用默认编辑器(如vi),把 <vcpu placement='static'>2</vcpu> 改成 4,保存退出即可。
4. 挂起与恢复
bash
# 挂起(相当于保存当前运行状态)
[root@server ~]# virsh suspend centos7-vm
域 centos7-vm 被挂起
# 恢复
[root@server ~]# virsh resume centos7-vm
域 centos7-vm 被重新恢复
五、 华为FusionCompute:企业级虚拟化平台的缩影
学完了底层的KVM,PPT里又带我们看了一下华为的FusionCompute虚拟化套件。它是企业级数据中心常用的商业软件,说白了也就是把KVM、QEMU这些底层技术做了个精美的"包装",加了强大的管理平台。
FusionCompute 主要分两个核心模块:
- CNA (Compute Node Agent):部署在物理服务器上,负责提供虚拟化计算资源,管理节点上的虚拟机。
- VRM (Virtual Resource Management):可以部署为虚拟机,提供WebUI,负责整个集群的资源调度、生命周期管理、网络、存储分发。
它的高级特性让人叹为观止:
- 热迁移(Live Migration):不停机把虚拟机从A物理机挪到B物理机。原理是内存压缩传输,磁盘数据位置不变(仅改映射),非常牛。
- 动态资源调度(DRS):集群负载不均衡时,自动把虚拟机迁移到较闲的机器上。
- 内存复用(内存气泡、共享、交换):把物理内存"超卖"。比如3个虚拟机共享同一块只读内存,用写时复制(COW)技术隔离,本来需要3G内存,可能只用1G就跑起来了,极客省钱。
- 分布式虚拟交换机(DVS):跨主机的虚拟交换机,不管虚拟机热迁移到哪台物理机,网络配置都不需要改。
六、 课后总结与踩坑反思
今天的理论课信息量极大,尤其是《1021实际学习内容》里关于CPU虚拟化 和内存虚拟化的拆解,让我真正明白了为什么早年"一核有难,多核围观"的虚拟机很卡,而现在的硬件辅助虚拟化(EPT、VT-x)能跑得飞快。
几个记忆犹新的点:
- x86那19条"敏感非特权指令"是万恶之源。
- GVA -> GPA -> HPA 的翻译链路,EPT直接硬件搞定,不再依赖复杂的影子页表。
- KVM只是内核模块,没有QEMU它就是个"光杆司令",两者缺一不可。
- 虚拟机只是一个普通的Linux进程,这句话越品越有味道。
踩过的坑(动手实操时):
在用 virsh edit 修改虚拟机配置时,如果不小心把XML标签写错了(比如少了闭合标签),重新启动虚拟机时就会报错 Error: internal error: Failed to parse XML。那时候别慌,系统提示的报错行号很清楚,顺着改回来就行。另外,如果是开启了SELinux的系统,虚拟机镜像文件的上下文权限不对(没有 virt_image_t 标签),虚拟机经常会报无权访问磁盘而启动失败。这个留到下一节课如果做实验再重点排查。
从虚机化的逻辑来看,如今云原生环境下的容器化(Docker)其实在理念上是一脉相承的。它们都在讲"隔离"(Namespace/Cgroups),都在讲"封装"(镜像),都在解决硬件与软件的紧耦合问题。
今天算是把虚拟化这层窗户纸捅破了。下一阶段,就要去接触更上层的云平台和容器技术了。继续加油,一步一步把云计算这棵大树的根摸透!