跳转至

虚拟机与容器

虚拟化让一台机器同时呈现多个相互隔离的运行环境。虚拟机虚拟化硬件接口,每个客体可运行自己的内核;容器虚拟化操作系统资源视图,多个容器共享宿主内核。

为什么需要虚拟化

  • 提高服务器利用率,把多个低负载系统合并到同一硬件。
  • 隔离租户、测试环境和故障。
  • 保存、迁移或复制完整运行环境。
  • 运行不同内核或旧系统。
  • 为应用提供一致部署依赖和资源限制。

虚拟化不是免费抽象。隔离边界越强,通常需要更多内存、设备仿真和转换;共享越多,效率越高,但共同故障域也越大。

虚拟机的基本结构

应用
客体操作系统
虚拟 CPU / 虚拟内存 / 虚拟设备
虚拟机监控器
物理硬件

虚拟机监控器 VMM/hypervisor 截获需要仲裁的操作,为客体提供接近真实硬件的接口。

  • Type 1 直接运行在硬件或高权限层。
  • Type 2 作为宿主操作系统上的程序运行。

分类边界在现代系统中可能模糊,重要的是实际谁负责 CPU、内存和设备虚拟化。

CPU 虚拟化

Trap-and-emulate

客体普通指令直接在物理 CPU 执行;敏感指令触发陷入,VMM 模拟期望效果。这样大多数计算接近原生速度,只有特权操作产生 VM exit。

早期某些体系结构的敏感指令不总能可靠陷入,曾需要二进制翻译,把危险指令动态改写为安全序列。硬件虚拟化扩展后来提供客体模式和更明确的拦截控制。

VM exit 的成本

退出客体要保存虚拟 CPU 状态、进入 VMM、处理原因再恢复。频繁特权操作、设备访问或中断会放大成本,因此会使用:

  • 半虚拟化接口,让客体以高效协议主动请求服务。
  • 批量操作和共享队列。
  • 直通或硬件辅助设备。
  • 减少不必要的拦截。

内存虚拟化

客体进程使用客体虚拟地址,客体内核认为自己管理“客体物理地址”,而 VMM 还要映射到宿主物理地址:

guest virtual
  -> guest page table
guest physical
  -> nested page table
host physical

硬件嵌套页表允许处理器完成两阶段翻译。代价是 TLB miss 后页表遍历更复杂,因此大页和 TLB 对虚拟机性能更重要。

VMM 还可使用气球驱动、内存超配、页共享或交换来管理物理内存。超配提高利用率,但多个客体同时增长工作集会造成严重回收和尾延迟。

设备虚拟化

设备模拟

模拟常见真实硬件,兼容不修改的客体驱动,但每次寄存器访问可能陷入,性能较低。

半虚拟化设备

客体使用面向虚拟环境的驱动,通过共享内存描述符环与 VMM 通信,减少模拟开销。

设备直通

把物理设备或硬件虚拟功能直接分配给客体,性能接近原生。需要 IOMMU 隔离,迁移、共享和管理灵活性降低。

容器的核心:共享内核

容器内应用仍发出宿主系统调用,进入同一个宿主内核。容器隔离主要由以下机制组合:

Namespace

改变进程看到的资源视图,例如:

  • 进程标识。
  • 挂载点和文件系统。
  • 网络接口与路由。
  • 主机名。
  • IPC 对象。
  • 用户与组身份映射。

namespace 回答“看见哪些对象和名字”。

cgroup

对一组进程统计和限制 CPU、内存、I/O、进程数等资源。cgroup 回答“能用多少、怎样计费和优先”。

namespace 没有限额,容器仍可能耗尽宿主资源;cgroup 没有独立视图,进程仍可能看到其他对象。二者解决不同问题。

分层文件系统与镜像

镜像由只读层组成,容器运行时增加可写层。相同基础层可共享,部署和回滚方便。

写时复制层适合短生命周期应用状态,不应把重要持久数据只留在可随容器删除的可写层。持久卷、备份和一致性协议仍需单独设计。

安全边界

容器还常结合:

  • capability 降权。
  • 系统调用过滤。
  • MAC 策略。
  • 只读挂载和设备限制。
  • 非 root 身份和用户 namespace。

容器共享宿主内核,因此内核漏洞可能跨越容器边界。高风险多租户场景可能在容器外再加虚拟机边界。

最小比较

维度 虚拟机 容器
内核 每个客体可独立 共享宿主内核
启动 通常较慢 通常较快
内存开销 包含客体内核与服务 主要是应用与共享页
运行不同 OS 内核 可以 通常不可以
隔离边界 虚拟硬件/VMM 宿主内核机制
设备访问 模拟、半虚拟化或直通 宿主设备接口与权限控制

这张表描述典型情况,不是绝对性能结论。精简虚拟机可以很快,复杂容器栈也可能很重。

一个容器资源例子

假设服务限制为 2 个 CPU 份额和 512 MiB 内存。限制不是给它“物理切下两个核心和一条内存”,而是由调度和内存控制机制在共享系统中实施配额、权重和回收策略。

当超过内存限制时,行为可能是回收、阻塞或在该控制组内选择终止进程,取决于配置和系统。应用仍需处理分配失败、延迟升高和终止,不应把容器限额当作透明硬件。

虚拟机快照与迁移

快照要捕获磁盘、内存和设备状态的一致切面。只复制内存而忽略外部网络、数据库或设备副作用,不一定能恢复完整业务状态。

在线迁移常迭代复制内存脏页,最后短暂停机复制剩余状态并切换。若页面被写脏速率高于网络复制速率,预复制难以收敛,需要限速、后复制或更长停机窗口。

容器不是打包格式而已

镜像提供文件系统内容,运行隔离还需要进程、namespace、cgroup、权限和网络配置。只解压镜像并运行进程,不会自动得到安全容器。

反过来,容器也不等于微服务。一个容器可运行单体应用,微服务也可运行在虚拟机或裸机。部署单位和软件架构是两个维度。

可观察性问题

虚拟化增加指标层次:

  • 客体看到的 CPU 忙可能包含被 VMM 暂停后的时间解释差异。
  • 容器内“可用内存”可能不同于宿主总内存和 cgroup 限额。
  • 设备延迟可能来自客体队列、VMM、宿主块层和物理设备。

诊断应同时观察客体/容器和宿主,避免只在一层下结论。

权衡与适用条件

选择虚拟机:

  • 需要不同内核或更强租户边界。
  • 需要完整系统兼容和设备模型。
  • 可以接受更高启动与内存成本。

选择容器:

  • 应用可共享宿主内核。
  • 关注快速部署、高密度和一致依赖。
  • 能正确配置最小权限与资源限制。

二者可以组合:每个租户一台虚拟机,内部用容器部署应用。

自测

  1. Trap-and-emulate 为什么能让多数普通指令接近原生执行?
  2. 两阶段地址翻译分别由谁维护?
  3. namespace 与 cgroup 各解决什么问题?
  4. 容器镜像的只读层为什么不等于完整安全隔离?
  5. 设备直通提高性能时牺牲了哪些能力?
参考思路

普通非敏感指令直接在硬件运行,只有特权事件退出。客体内核维护 guest virtual 到 guest physical,VMM 维护到 host physical。namespace 改变视图,cgroup 管资源。镜像只是文件内容。直通降低模拟开销,却影响共享、迁移和管理,并要求严格 IOMMU 隔离。