CodeStats | 资深底层技术爱好者与实战派架构师,WWAIC(全周 AI 编程)范式创始人
专注计算机体系结构、操作系统内核、Java 虚拟机实现原理与自研框架落地。本文手撕虚拟机底层:不讲空话,只从 CPU 指令 → 操作系统 → 进程 → 硬件虚拟化这条铁链,彻底讲透虚拟机是什么、凭什么能隔离、和 Docker 容器到底有什么区别。
参考原文(CSDN) :从 CPU 指令到容器隔离:Docker 就是一个打了标签的普通进程
📖 本文你能获得什么
程序运行的本质:CPU 取指执行 + 操作系统调度 = 进程的"虚拟 CPU"假象
CPU 权限分级:彻底搞懂 ring 0 / ring 3、内核态/用户态、系统调用
虚拟机执行原理:Guest OS 如何"骗过"CPU ------ 从 Trap & Emulate 到 Intel VT-x 硬件辅助虚拟化
设备模拟真相:硬盘、网卡全是 QEMU 用软件"演"出来的(镜像文件、TAP 设备、virtio)
隔离本质对比:虚拟机隔离"硬件"(独立内核)vs Docker 隔离"名字空间"(共享内核)
技术选型框架:什么时候选虚拟机,什么时候选 Docker,一张表+一句话秒懂
适合谁看:资深底层技术爱好者、实战派架构师、云原生开发者,以及任何想彻底搞懂"虚拟机到底是个什么东西"的人。
目录
- 核心观点一句话
- 提问一:程序运行的本质是什么?
- [提问二:CPU 权限管控和内核态、用户态是什么关系?](#提问二:CPU 权限管控和内核态、用户态是什么关系?)
- 提问三:虚拟机是如何通过用户态进程执行内核态权限指令的?
- 提问四:虚拟机是如何解决硬盘和网卡模拟的?
- 提问五:虚拟机隔离的本质是什么?一句话总结
- [提问六:虚拟机和 Docker 区别对比及各场景一句话总结](#提问六:虚拟机和 Docker 区别对比及各场景一句话总结)
- [本质升华:一台机器 vs 一个进程](#本质升华:一台机器 vs 一个进程)
核心观点一句话
虚拟机 = 硬件模拟(CPU/内存/硬盘/网卡)+ 独立 Guest OS + 完整隔离边界
它不共享宿主机内核,它是宿主机上一个被赋予了"完整硬件视图"的普通进程。
提问一:程序运行的本质是什么?
程序运行的本质 = CPU 从内存中逐条取指令、执行指令的过程。
一个程序本身只是存放在磁盘上的一组指令和静态数据,没有生命周期。是操作系统把程序代码加载到内存中,生成相应的数据结构(进程控制块、内存映射表等),然后从代码的起始位置读取指令交给 CPU 顺序执行。
CPU 本质上就是一个"去内存中根据地址取指令,然后执行指令的硬件"。指令执行过程中可能遇到跳转指令(循环、条件判断最终都被编译为跳转指令),CPU 的下一条指令就不再是内存中顺序的下一条。
从 CPU → 操作系统 → 应用程序的完整链条是:
| 层级 | 职责 |
|---|---|
| CPU | 取指、译码、执行,只认机器指令 |
| 操作系统 | 加载程序、调度进程、管理内存、提供系统调用接口 |
| 应用程序 | 在操作系统之上运行,通过系统调用请求内核服务 |
操作系统提供了"存在多个虚拟 CPU"的假象,让每个进程都以为自己独占整台机器。每个进程被分配一个虚拟地址空间(32 位 Linux 为 4GB),通过 MMU 映射到真实物理内存。
提问二:CPU 权限管控和内核态、用户态是什么关系?
CPU 权限管控 = 通过指令集特权级划分,将操作系统和用户程序运行在不同权限级别上。
Intel x86 CPU 用 ring 0(内核态) 和 ring 3(用户态) 来划分权限:
| 运行态 | 特权级 | 能力 |
|---|---|---|
| 内核态 (Ring 0) | 最高 | 可执行任何 CPU 指令,直接操作硬件,访问所有内存地址 |
| 用户态 (Ring 3) | 最低 | 只能执行受限指令,访问受限资源,不能直接访问硬件 |
内核态和用户态的关系:
有一类指令叫特权指令 (如读写硬盘、修改内存映射表),一旦用错,整个操作系统会直接宕机。因此,普通程序要访问硬件,必须通过系统调用(System Call)陷入内核,让内核代劳。
当用户态程序发起系统调用时,CPU 会从 ring 3 切换到 ring 0,跳转到内核代码位置执行,完成后再从 ring 0 返回 ring 3。
这一层奠定了"权限分级控制"的基础。
提问三:虚拟机是如何通过用户态进程执行内核态权限指令的?
核心答案:通过「Trap & Emulate」(陷阱+模拟)或「硬件辅助虚拟化」技术。
虚拟机(如 KVM + QEMU)本身是宿主机上的一个用户态进程,但 Guest OS 内部有自己的内核态和用户态。问题在于:Guest OS 认为自己运行在 ring 0,但实际它在宿主机上只是一个用户态进程,没有真正的 ring 0 权限。
解决方案有两种:
1. 纯软件模拟(Trap & Emulate)
当 Guest OS 执行一条特权指令时,由于它实际运行在用户态,CPU 会触发一个陷阱(Trap) ,陷入宿主机内核。宿主机内核(或 VMM)捕获这个陷阱后,模拟执行这条指令,然后把结果返回给 Guest OS。
这种方式叫"陷阱-模拟"------敏感指令被捕获,由软件模拟执行。
缺点是性能差:每条特权指令都要触发陷阱、陷入内核、模拟执行、返回。
2. 硬件辅助虚拟化(Intel VT-x / AMD-V)
现代 CPU 提供了专门的虚拟化指令集(Intel VT-x、AMD-V)。KVM 利用这些硬件能力,让 Guest OS 的指令直接在 CPU 上运行,不需要软件模拟。
工作流程如下:
- 用户态的 QEMU 通过
ioctl系统调用进入 KVM 内核模块 - KVM 为虚拟机创建虚拟 CPU(vCPU)和虚拟内存
- 执行
VMLAUNCH指令,CPU 进入客户模式(Guest Mode) - Guest OS 在客户模式下直接运行,大部分指令由硬件直接执行
- 遇到敏感操作时,CPU 自动退出客户模式,由 KVM 处理
一句话总结:虚拟机不是"在用户态执行内核指令",而是通过硬件虚拟化扩展,让 Guest OS 运行在一个特殊的"客户模式"下,敏感指令由 VMM 捕获并模拟。
提问四:虚拟机是如何解决硬盘和网卡模拟的?
核心答案:通过「设备模拟」------在虚拟机监控器(VMM)中用软件模拟硬件设备的行为。
虚拟机需要让 Guest OS 认为自己有真实的硬盘和网卡。但实际上,这些都是软件模拟出来的。
硬盘模拟
在宿主机上创建一个镜像文件 (如 .qcow2 或 .raw),作为虚拟磁盘。当 Guest OS 发起磁盘 I/O 请求时:
- Guest OS 的驱动程序向"虚拟硬盘"发出读写指令
- 这些指令被 VMM(如 QEMU)捕获
- QEMU 将指令转换为对宿主机镜像文件的读写操作
- 结果返回给 Guest OS
网卡模拟
类似地,QEMU 模拟一个标准的网卡设备(如 Intel e1000)。Guest OS 看到的是一块真实的物理网卡,实际上所有网络数据包都由 QEMU 处理:
- Guest OS 发送数据包到"虚拟网卡"
- QEMU 捕获数据包
- QEMU 通过宿主机的网络栈(如 TAP 设备、网桥)将数据包发出
- 收到的数据包由 QEMU 注入到 Guest OS 的"虚拟网卡"
I/O 虚拟化的三种方式
| 方式 | 原理 | 性能 |
|---|---|---|
| 设备模拟(全虚拟化) | 纯软件模拟硬件设备 | 最低 |
| 半虚拟化(virtio) | Guest OS 知道自己被虚拟化,与 VMM 协作 | 较高 |
| 设备直通(PCI Passthrough) | 直接将物理设备分配给虚拟机 | 最高 |
一句话总结:硬盘和网卡的模拟,本质是 VMM 在宿主机上"假装"成硬件设备,拦截 Guest OS 的 I/O 请求并转换为对宿主机资源的操作。
提问五:虚拟机隔离的本质是什么?一句话总结
虚拟机隔离的本质 = 通过 VMM(虚拟机监控程序)在硬件层面模拟出多台独立的"物理机器",每台虚拟机拥有独立的 CPU、内存、硬盘、网卡和操作系统内核,彼此之间完全不可见、不可访问。
一台虚拟机的崩溃(操作系统故障、应用程序崩溃、驱动程序故障)不会影响同一物理服务器上的其他虚拟机。每个虚拟机都像运行在独立的物理机器上一样。
虚拟机的隔离是硬件级别的强隔离,因为它模拟的是完整的硬件边界。
提问六:虚拟机和 Docker 区别对比及各场景一句话总结
对比表格
| 维度 | 虚拟机(KVM) | 容器(Docker) |
|---|---|---|
| 隔离边界 | 硬件(模拟完整硬件) | 内核(系统调用接口) |
| 独立内核 | 每个虚拟机一个 Guest OS 内核 | 无,共享宿主机内核 |
| 启动时间 | 分钟级 | 毫秒级 |
| 资源开销 | GB 级别 | MB/KB 级别 |
| 隔离级别 | 强(硬件辅助虚拟化) | 中(内核 Namespace) |
| 本质 | 模拟硬件,跑操作系统 | 隔离进程,跑应用 |
各场景一句话总结
| 场景 | 一句话推荐 |
|---|---|
| 需要运行不同内核的操作系统(如在 Linux 上跑 Windows) | 选虚拟机,因为容器共享宿主机内核,无法运行不同内核的 OS |
| 多租户环境、遗留应用迁移、强安全隔离要求 | 选虚拟机,硬件级隔离更彻底 |
| 微服务架构、云原生应用、快速弹性伸缩 | 选 Docker,轻量快速,资源利用率极高 |
| 快速开发、测试和部署,大规模应用分发 | 选 Docker,秒级启动,镜像分层复用 |
| 传统 IT 环境中的服务器虚拟化项目 | 选虚拟机,成熟稳定,隔离性好 |
| 混合部署(需要兼顾隔离和效率) | 两者结合:在虚拟机中运行多个 Docker 容器 |
本质升华:一台机器 vs 一个进程
纵观全文,从CPU指令到设备模拟,虚拟机和Docker给出了两种截然不同的"隔离"答卷:
-
虚拟机(KVM)的隔离思想是"向下切割硬件" :它通过VMM在物理硬件层面 模拟出独立的CPU、内存、硬盘和网卡,每一台虚拟机都拥有自己独立的操作系统内核。虚拟机本质是在硬件边界上筑墙------墙内系统崩溃(如内核Panic),墙外宿主机和其他虚拟机毫无感知。这是一种**"物理机器级"的强隔离**,重资产,但绝对彻底。
-
Docker容器的隔离思想是"向上圈定进程" :它不模拟任何硬件,而是利用Linux内核的命名空间(Namespace)在操作系统层面 给进程打上"视野标签"(独立的PID、网络、文件系统等),再用Cgroups划定资源使用上限。Docker本质是在操作系统边界上画圈------所有容器共享宿主机同一个内核,隔离的是"进程能看到什么、能用多少资源",而非硬件本身。这是一种**"进程级"的轻量隔离**,快如闪电,但共享内核风险。
一句话记住它们
虚拟机隔离的是"硬件" ,所以它能跑Windows也能跑Linux,不依赖宿主机内核,防的是"物理故障和内核崩溃" ;
Docker隔离的是"操作系统名字空间" ,所以它只能跑与宿主机同内核的应用,防的是"进程干扰和文件冲突"。
思想终极提炼
- 虚拟机的核心思想 :"把一台物理主机,变成多台虚拟主机" ------ 解决的是"硬件资源池化与多系统共存"问题。
- Docker的核心思想 :"把一台物理主机上的进程,安排得明明白白" ------ 解决的是"应用交付与环境依赖一致性"问题。
在技术选型的天平上:
- 如果你担心内核级漏洞 或需要运行异构OS,请把砝码压在虚拟机(硬件墙)上;
- 如果你追求极致弹性 、微服务迭代 和资源利用率,请把砝码压在Docker(进程标签)上。
记住:虚拟机动的是"地基"(硬件),Docker改的是"门牌号"(命名空间)。地基隔开的是整栋楼,门牌号隔开的是同一栋楼里的不同房间。
最后:点赞 · 收藏 · 评论
如果这篇文章帮你彻底搞懂了虚拟机的底层原理,并理清了它与Docker的本质区别:
- 👍 点赞 让更多同学看到这篇硬核推演
- ⭐ 收藏 方便随时复习完整逻辑链
- 💬 评论 留下疑问或补充
从 CPU 指令到硬件虚拟化,从硬件墙到命名空间标签------你已掌握云计算虚拟化技术的两大基石。
© 2026 CodeStats | 原创不易,转载注明出处