因为容器没有虚拟出一台完整的机器,它只是把宿主机上的一组进程“隔离起来运行”。最核心区别是:
- 容器: 共享宿主机内核
- 虚拟机: 有自己的独立内核
容器本质上还是宿主机进程#
比如你启动一个 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 namespace | cgroup 视图 | 隐藏宿主机真实的资源控制层级 |
| 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、Kubernetes | VMware、KVM、QEMU、VirtualBox |