跳过正文
  1. 所有文章/

为什么容器不是虚拟机

·1724 字·4 分钟
目录

因为容器没有虚拟出一台完整的机器,它只是把宿主机上的一组进程“隔离起来运行”。最核心区别是:

  • 容器: 共享宿主机内核
  • 虚拟机: 有自己的独立内核

容器本质上还是宿主机进程
#

比如你启动一个 Docker 容器:

docker run nginx

看起来像是启动了一个“小系统”,但本质上宿主机里只是多了几个普通 Linux 进程。

容器里的 nginx:

在容器里看:PID 1
在宿主机看:普通进程,比如 PID 12345

它不是运行在一台虚拟电脑里,而是运行在宿主机 Linux 内核上。

虚拟机会虚拟硬件,容器不会
#

虚拟机结构
#

虚拟机通常有:

  • 虚拟 CPU
  • 虚拟内存
  • 虚拟网络
  • 虚拟磁盘
  • 虚拟 BIOS/UEFI
  • Guest OS 内核

虚拟机结构类似:

物理硬件
  └── Hypervisor
        └── 虚拟硬件
              ├── vCPU
              ├── 虚拟内存
              ├── 虚拟磁盘
              ├── 虚拟网卡
              ├── 虚拟主板/PCI
              └── 虚拟 BIOS/UEFI
                    └── 虚拟机
                          ├── Guest OS 内核
                          └── 应用程序

容器结构
#

容器结构类似:

物理硬件
  └── 宿主机内核
        ├── 容器 A 进程
        ├── 容器 B 进程
        └── 容器 C 进程

容器没有自己的内核,也没有完整虚拟硬件。

容器只是做了隔离和限制
#

容器主要靠 Linux 的这些机制实现:

  • namespace:隔离看到的资源
  • cgroups:限制资源使用
  • capabilities:限制 root 权限
  • seccomp/AppArmor/SELinux:限制系统调用和访问权限

它让进程“看起来像在独立环境里”,例如:

  • 有自己的进程列表
  • 有自己的网络栈
  • 有自己的文件系统视图
  • 有自己的 hostname
  • 有自己的用户 ID 映射

但底层内核仍然是宿主机内核。

namespace 到底隔离了什么
#

Linux 里常见 namespace 有这些:

Namespace隔离内容效果
PID namespace进程号空间容器里可以看到自己的 PID 1,看不到宿主机其他进程
Mount namespace文件系统挂载点容器有自己的根目录 /、挂载表
Network namespace网络设备、IP、路由、防火墙规则容器有自己的网卡、IP、端口空间
IPC namespace进程间通信资源隔离共享内存、信号量、消息队列
UTS namespace主机名、域名容器可以有自己的 hostname
User namespace用户和用户组 ID 映射容器内的 root 不一定是宿主机 root
Cgroup namespacecgroup 视图隐藏宿主机真实的资源控制层级
Time namespace系统时间视图允许不同 namespace 看到不同的启动时间/单调时间偏移

所以 namespace 隔离的是:

  • 进程列表
  • 文件系统挂载
  • 网络栈
  • 用户身份
  • 主机名
  • IPC 资源
  • cgroup 视图
  • 部分时间视图

但它不隔离:

  • Linux 内核本身
  • 内核漏洞
  • CPU 指令集
  • 真实硬件
  • 内核模块
  • 大部分系统调用实现

容器和虚拟机隔离的核心区别
#

namespace是操作系统级隔离: 同一个内核,不同的资源视图

虚拟机是硬件级/机器级隔离: 不同的虚拟硬件,不同的操作系统内核

容器
#

容器通常基于:

namespace + cgroups + capabilities + seccomp + AppArmor/SELinux

它的结构是:

宿主机硬件
  └── 宿主机内核
        ├── 容器 A 进程
        ├── 容器 B 进程
        └── 容器 C 进程

特点:

  • 所有容器共享同一个宿主机内核
  • 隔离的是“资源视图”
  • 启动快
  • 开销小
  • 密度高
  • 安全边界弱于虚拟机

虚拟机
#

它的结构是:

宿主机硬件
  └── Hypervisor / 虚拟化层
        ├── VM A:自己的内核 + 用户空间
        ├── VM B:自己的内核 + 用户空间
        └── VM C:自己的内核 + 用户空间

特点:

  • 每个 VM 有自己的操作系统内核
  • 隔离的是“完整机器”
  • 可以跑不同 OS,例如 Linux 宿主机上跑 Windows VM
  • 隔离更强
  • 开销更大
  • 启动更慢

安全性区别
#

容器风险
#

因为容器共享宿主机内核,所以如果容器内进程利用了内核漏洞,可能逃逸到宿主机。

例如:

容器进程 → 系统调用 → 宿主机内核

容器和宿主机之间的边界主要靠 Linux 内核功能限制。

虚拟机风险
#

虚拟机攻击路径通常是:

VM 内进程 → Guest OS 内核 → 虚拟硬件 → Hypervisor → 宿主机

攻击面更深一层,逃逸难度通常更高。

所以一般认为:虚拟机隔离强于容器隔离,但容器性能和启动速度更好。

为什么 Docker 看起来像虚拟机
#

因为容器提供了很多“像系统一样”的东西:

  • 独立的文件系统
  • 独立的网络
  • 独立的进程空间
  • 可以安装软件包
  • 可以进入 shell

所以你进入容器后:

docker exec -it xxx -- bash

会感觉像登录了一台小 Linux,但这只是用户空间环境,不是完整操作系统,它缺少自己的内核:

容器镜像 = 用户态文件系统 + 应用依赖
虚拟机 = 完整 OS + 内核

例如一个 Ubuntu 容器里有:

/bin/bash
/usr/bin/apt
/lib
/etc

但没有真正运行自己的 Ubuntu 内核,它调用的仍然是宿主机 Linux 内核。

对比总结
#

对比项Namespace / 容器虚拟机
隔离层级操作系统级硬件/机器级
是否共享宿主机内核
是否有独立内核
启动速度秒级甚至毫秒级通常更慢
资源开销
隔离强度较弱较强
适合场景微服务、应用部署、CI/CD强隔离、多 OS、云主机
典型技术Docker、containerd、KubernetesVMware、KVM、QEMU、VirtualBox