虚拟化与容器:Hypervisor、namespace 与 cgroup
虚拟化用 Hypervisor 把一台物理机软件再造为多台整机(VM),容器则用 namespace(视图隔离)+ cgroup(资源限额)+ 联合文件系统(COW 镜像层)在同一内核上隔离出多份"系统视图"。
一句话定义
虚拟化用 Hypervisor 把一台物理机软件再造为多台整机(VM),容器则用 namespace(视图隔离)+ cgroup(资源限额)+ 联合文件系统(COW 镜像层)在同一内核上隔离出多份"系统视图"。
为什么重要
云与云原生的全部地基。VM 与容器的取舍(隔离强度 vs 启动与密度)是每个架构评审的必答题;而它们的机制完全长在本书前几章上——页表(kp-017)延伸出 EPT、fork(kp-007)延伸出镜像层 COW、调度与内存管理延伸出 cgroup。这是知识树收束成"一张网"的最佳位置。
前置知识
kp-017(分页与页表);kp-008(进程与资源封装)。
核心概念
- Hypervisor(VMM):创建与调度虚拟机的软件;Type 1 裸金属(Xen/ESXi/KVM 内建),Type 2 宿主型(VirtualBox)。
- 陷入-模拟(trap-and-emulate):客户机执行特权指令时陷入 Hypervisor,由其模拟效果。
- 硬件辅助虚拟化:VT-x/AMD-V 提供客户态与根态;EPT/NPT 让两级地址翻译由硬件完成。
- 半虚拟化(virtio):客户机自知虚拟化,用约定接口直通驱动,减少陷入。
- namespace:PID/网络/挂载/UTS/IPC/用户/Cgroup 七类视图隔离,容器"看不到"外界的机制。
- cgroup:对一组进程做 CPU/内存/IO/PID 限额与统计。
- overlayfs 镜像层:只读层 + 可写层的 COW 叠加,镜像瘦身的来源。
原理与机制
栈结构对比:
VM: [App][App] [Guest内核(完整OS)] <- 每台VM带一份内核
[ Hypervisor / KVM ]
[ 宿主内核 ] [硬件]
容器: [App][App][App] <- 共享宿主内核, 只有用户态
[容器引擎(runtime): namespace+cgroup+overlayfs]
[宿主内核] [硬件]
隔离层级差异是所有取舍的根源:VM 的边界是硬件虚拟化,客户内核可以任意打补丁、换版本,安全边界强;容器的边界是内核内的一组检查点,共享内核意味着内核漏洞即容器逃逸面。EPT 的两级翻译(GVA → GPA → HPA)是 kp-017 单级翻译的硬件扩展,其 TLB 未命中代价催生了huge page 与 TLB shootdown 优化等专门课题。
cgroup v2 的统一层级:/sys/fs/cgroup/<组>/ 下 cpu.max(配额)、memory.max(硬限,超限触发该组 OOM,逻辑同 kp-019)、io.max 等——容器限额没有魔法,就是把这组文件设值。
图示
启动密度与开销谱系:
裸金属 <- 容器(毫秒启动, 数百实例/机) <- 微VM(Firecracker, 折中) <- VM(秒级, 隔离最强)
直观类比
VM 像在楼里给每户盖独立小屋(自带水电系统=客户内核),绝对独立但造价高;容器像同一栋楼里砌隔断墙并装独立水表电表(namespace+cgroup),便宜灵活,但整栋楼共用一套主体结构(内核)——主体出问题,所有隔间一起遭殃。
实例或案例
unshare --pid --fork --mount-proc bash; ps aux # 新PID namespace里只看到自己
lsns # 列出系统的全部 namespace
cat /sys/fs/cgroup/system.slice/docker-*.scope/memory.max # 容器内存限额(v2)
docker/podman run --memory=100m --cpus=0.5 ... # 限额即写 cgroup 文件
podman images --tree # 镜像分层与共享层可视化(overlayfs 的 COW)
无 Docker 也能理解容器:unshare + 写几个 cgroup 文件 + chroot,就是一个最小容器——很多教学项目(如"100 行写一个容器")正是这么做的。
常见误区
- 认为容器 = 轻量级 VM 所以安全等级相同:隔离路径完全不同,多租户强隔离场景需微 VM 或安全容器(Kata/gVisor)。
- 认为容器里
top显示的核数就是限额:namespace 内工具常读到宿主视角,CPU 限额由 cgroup 配额实现,JVM 等运行时需显式感知。 - 把镜像当虚拟机磁盘:镜像只是分层只读文件系统,容器运行时的可写层是临时 COW 层,销毁即丢。
与其他知识点的关系
EPT 是 kp-017 的虚拟化延伸;overlayfs 是 kp-025 COW 与 kp-007 写时复制的同族思想;cgroup 内存限额直接调用 kp-019 的回收与 OOM 机制。
延伸阅读
Popek & Goldberg 1974 虚拟化判据论文;kernel 文档 namespaces(7)、cgroups(7);Firecracker 论文(NSDI 2020)。
自测题
- VM 与容器隔离边界的本质差别?
答:VM 以 Hypervisor + 硬件虚拟化为边界,客户有独立内核;容器以共享内核上的 namespace/cgroup 检查为边界,内核漏洞可致逃逸。
- EPT 解决了什么性能问题?
答:软件影子页表需用内存模拟两级翻译且同步代价高;EPT 让 GVA→GPA→HPA 由硬件一次完成,代价是 TLB 未命中成本上升,故常配大页。
- 容器的 CPU 限额是如何实现的?
答:cgroup 的 cpu.max 写入配额与周期(如 50ms/100ms 即半核),调度器据此限制该组进程的时间片总量。