容器共享内核 → 隔离不如虚机 → 但够用吗?答案取决于你的威胁模型。
一、先看图
flowchart TD
VM[虚拟机<br/>独立内核] --> HYPERVISOR[Hypervisor<br/>硬件隔离]
MICROVM[microVM<br/>Firecracker/Kata] --> HYPERVISOR
CONTAINER[容器<br/>共享内核] --> NS[namespace<br/>视图隔离]
CONTAINER --> CG[cgroup<br/>资源限制]
CONTAINER --> SEC[seccomp<br/>syscall 过滤]
CONTAINER --> CAP[capabilities<br/>权限限制]
classDef strong fill:#3fb95022,stroke:#3fb950,color:#adbac7;
classDef medium fill:#f0883e22,stroke:#f0883e,color:#adbac7;
classDef weak fill:#f8514922,stroke:#f85149,color:#adbac7;
class VM,HYPERVISOR strong
class MICROVM medium
class CONTAINER,NS,CG,SEC,CAP weak
二、容器隔离层
| 层 | 机制 | 保护 |
|---|---|---|
| 视图 | namespace | 进程/网络/文件系统隔离 |
| 资源 | cgroup v2 | CPU/内存/IO 限制 |
| 系统调用 | seccomp-bpf | 禁止危险 syscall |
| 权限 | capabilities | 最小权限 |
| 文件系统 | overlay + read-only | 不可变基础层 |
| MAC | SELinux/AppArmor | 强制访问控制 |
三、共享内核的风险
3.1 内核漏洞
容器和宿主共享同一个内核 → 内核漏洞 = 逃逸路径。
历史逃逸案例:
- CVE-2019-5736(runc)
- CVE-2020-15257(containerd)
- CVE-2022-0185(fsconfig)
3.2 未 namespace 化的接口
/proc/sys/部分参数全局共享- 某些 ioctl 不受 namespace 限制
- 时间(直到 time namespace 出现)
四、User Namespace Rootless
podman run --userns=auto my_app容器内 root → 映射到宿主非特权 UID → 即使逃逸也只是普通用户。
五、gVisor
Google 的用户态内核:
应用 → gVisor Sentry(用户态内核) → 有限 syscall → 宿主内核
- 拦截所有 syscall → 在用户态重新实现
- 大幅减少内核攻击面
- 代价:兼容性和性能
六、Kata Containers
应用 → 容器 → 轻量级 VM → 宿主内核
每个容器(或 pod)跑在独立的微虚拟机中 → 独立内核 → 硬件隔离。
启动时间 ~100ms → 接近容器。
七、Firecracker
AWS Lambda/Fargate 的基础:
应用 → Firecracker microVM → KVM → 宿主
- 精简的 VMM → 只有必要的设备模型
- 启动 < 125ms,内存 < 5MB overhead
- 硬件隔离 + 容器级敏捷
八、隔离强度对比
| 方案 | 内核隔离 | 启动时间 | 兼容性 | 适用场景 |
|---|---|---|---|---|
| 容器 | 共享 | ms | 最好 | 可信工作负载 |
| gVisor | 用户态内核 | ms | 中等 | 多租户 |
| Kata | 独立内核 | ~100ms | 好 | 强隔离需求 |
| Firecracker | 独立内核 | ~100ms | 好 | 云函数/多租户 |
| 传统 VM | 独立内核 | 秒级 | 最好 | 最强隔离 |
九、观察
# 当前容器安全配置
docker inspect --format '{{json .HostConfig.SecurityOpt}}' my_container
docker inspect --format '{{json .HostConfig.CapDrop}}' my_container
# user namespace
cat /proc/self/uid_map
# seccomp 状态
grep Seccomp /proc/1/status
# 内核漏洞检查
grep . /sys/devices/system/cpu/vulnerabilities/*十、小结
- 容器隔离 = namespace + cgroup + seccomp + capabilities
- 共享内核 = 内核漏洞可能导致逃逸
- User namespace rootless 降低逃逸影响
- gVisor/Kata/Firecracker 提供更强隔离
- 选择取决于威胁模型和性能需求
参考文献
- gVisor documentation (gvisor.dev)
- Kata Containers architecture (katacontainers.io)
- Firecracker design (firecracker-microvm.github.io)
- NCC Group, “Understanding and Hardening Linux Containers.” 2016
工具
podman/dockerrunsc(gVisor)kata-runtimefirecracker
文章导航
分类入口
读完这篇,下一步读什么
优先读同系列或同问题的下一篇,把单篇消费变成主题集群。
【从零造容器】microVM 实战:Firecracker API 启动与容器对比实测
手把手用 Firecracker REST API 与 config-file 拉起 KVM microVM;实测 WSL2 启动时延,对比 unshare 容器隔离;附 Firecracker、gVisor、Kata、Cloud Hypervisor 选型表。
CPU 调度:CFS 的虚拟运行时间与 EEVDF 的虚拟截止期
从比例份额调度的论文谱系出发,对照 Linux v6.6 与 v6.12 fair.c 源码,解释 CFS 的 vruntime、EEVDF 的 lag/eligible/deadline,并用确定性模拟复现延迟与 lag 的差异。
I/O 调度:在寻道、队列深度与公平性之间取舍
从电梯算法到 blk-mq,解释 Linux I/O 调度器为何在 HDD 上排序、在共享设备上保公平、在 NVMe 上常选择 none,并用确定性模拟展示寻道距离与队列尾延迟的取舍。
用户态内存分配器:size class、线程缓存与碎片边界
从 Wilson 分配器综述到 jemalloc、gperftools tcmalloc 与 mimalloc 的源码路径,解释 size class、线程缓存、跨线程释放和 RSS 碎片;用可复现实验说明不能只凭 allocator 名字下结论。