容器如何使用硬件资源
下面是一份把“容器如何使用硬件资源”从内核路径一次性讲透的总结。
不是 “容器怎么用 CPU/内存” 的表面答案,而是 “请求是如何从容器 -> 内核 -> 硬件”。
按 总体模型 -> CPU -> 内存 -> 存储 -> 网络 -> 资源隔离与限制的协同 来讲。
容器不是虚拟硬件,而是:一组受限的 Linux 进程。
本质公式
容器 = Namespace(看不见别人)
+ cgroups(用不多、用不超)
+ Linux 内核(真正访问硬件)
📌 没有 Hypervisor,没有虚拟 CPU,没有虚拟内存控制器
容器进程 = 普通 Linux 进程
CPU 调度仍然是:
- CFS(Completely Fair Scheduler)
- RT / DL(实时调度)
核心控制点
/sys/fs/cgroup/<container>/cpu.max
示例:
cpu.max = 50000 100000
含义:
- 每 100ms
- 最多跑 50ms(50% CPU)
容器进程
-> CFS 调度队列
-> cgroup 限额检查
-> CPU 核心
📌 CPU 是“时间片限制”,不是“核数隔离”
cpuset.cpus = 0-3
效果:
- 容器只会在指定 CPU 上运行
- NUMA 场景非常重要
- 节点过载
- CPU quota 太小
- 同 cgroup 内部竞争
- 没有“容器内存”
- 所有内存来自宿主机
memory.max
memory.current
memory.swap.max
malloc()
-> glibc
-> brk / mmap
-> 内核页分配器
-> cgroup memory 计数
-> 物理内存
memory.current > memory.max
-> cgroup OOM
-> kill 容器内进程
所有容器 + 宿主机 > 物理内存
-> 系统级 OOM
-> 可能杀宿主机关键进程
📌 容器内存限制 ≠ 系统安全
- 文件缓存不完全受限
- 容器 IO 会污染宿主机 cache
容器 rootfs
= overlayfs 视图
= VFS 层
容器进程
-> VFS
-> OverlayFS
-> 实际文件系统(ext4 / xfs)
-> Block Layer
-> IO Scheduler
-> 磁盘
- metadata 操作多
- copy-up 成本高
- fsync 行为复杂
📌 这是容器磁盘性能波动的根源
io.max
io.bfq.weight
示例:
io.max = 8:0 rbps=10M wbps=5M
- rename 非原子
- fsync 不可靠
- inode 不稳定
👉 必须用 bind mount / volume
容器拥有:
- 独立网卡视图
- 独立路由表
- 独立 iptables
容器 eth0 ←-> vethXXX ←-> 宿主机
容器进程
-> socket
-> netns
-> veth
-> bridge / ovs
-> iptables / nftables
-> 物理网卡
- 容器 IP 通常是私有
- 宿主机负责地址转换
- veth copy
- conntrack
- iptables 规则过多
📌 高性能场景:
- hostNetwork
- SR-IOV
- DPDK
| 组件 | 作用 |
|---|---|
| Namespace | “看不见别人” |
| cgroups | “用不多、不超用” |
| Scheduler | 实际分配 |
| VFS / Net | 抽象硬件 |
| 维度 | 容器 | 虚拟机 |
|---|---|---|
| CPU | 时间片限制 | vCPU |
| 内存 | 共享物理内存 | 虚拟内存 |
| 内核 | 共用 | 独立 |
| IO | 共用 block 层 | 虚拟磁盘 |
| 安全边界 | 进程级 | 硬件级 |
📌 容器是“调度隔离”,VM 是“硬件隔离”
-> 错,是限制,不是拥有
-> 错,宿主机仍可能 OOM
-> 错,共享 block 层
容器访问资源的本质:进程 -> 内核 -> 硬件,cgroups 只是“阀门”,Namespace 只是“遮罩”。