Linux cgroups
cgroups = Linux 内核的「资源配额与控制系统」
如果说:
- Namespace:你 能看到什么
- cgroups:你 能用多少
那么 容器 = Namespace + cgroups
| 资源 | 能控制什么 |
|---|---|
| CPU | 使用比例、上限、调度 |
| Memory | 最大内存、OOM 行为 |
| I/O | 磁盘读写限速 |
| PIDs | 最大进程数 |
| Network | 间接(通过 tc / BPF) |
| HugePages | 巨页配额 |
| Devices | 设备访问 |
- 多层级、多 controller
- 每个 controller 一棵树
- 混乱、容易配置错
/sys/fs/cgroup/memory
/sys/fs/cgroup/cpu
/sys/fs/cgroup/blkio
- 单一层级
- 统一接口
- 更强的资源模型
/sys/fs/cgroup/
├── cgroup.controllers
├── cgroup.subtree_control
├── cpu.max
├── memory.max
├── io.max
📌 RHEL 8+ / Debian 11+ 推荐只用 v2
所有资源:
/sys/fs/cgroup/
echo "+cpu +memory" > cgroup.subtree_control
子组的资源不能超过父组
cpu.max = <quota> <period>
- 100000 100000 = 1 core
- 200000 100000 = 2 cores
- max 100000 = 不限
cpu.weight = 1 ~ 10000
📌 默认 100
memory.max = 512M
超出:
- OOM kill
- 不影响宿主
memory.high = 400M
- 超过 -> 回收 / throttling
- 不直接 OOM
memory.swap.max = 0 # 禁用 swap
实时使用量
io.max="8:0 rbps=10M wbps=5M"
pids.max = 256
v2 不再推荐直接用 devices
-> eBPF / LSM
echo <pid> > cgroup.procs
- 每个 service / slice 都是 cgroup
- systemd 只支持 v2(RHEL 9)
/
├── system.slice
│ └── sshd.service
├── user.slice
│ └── user-1000.slice
└── machine.slice
└── docker-xxx.scope
[Service]
MemoryMax=1G
CPUQuota=200%
TasksMax=512
docker run -m 512m --cpus=1 nginx
-> 转换为:
- memory.max
- cpu.max
| Pod 配置 | cgroup 映射 |
|---|---|
| limits.memory | memory.max |
| requests.cpu | cpu.weight |
📌 requests ≠ limits
- 默认不绑定 NUMA
- 可结合:
- cpuset.cpus
- cpuset.mems
cpuset.cpus=0-7
cpuset.mems=0
📌 数据库强烈建议
memory.oom.group=1
- 整个 cgroup 一起 kill
- 防止“半死不活”
stat -fc %T /sys/fs/cgroup
- cgroup2fs -> v2
cat /proc/<pid>/cgroup
cat memory.current
cat cpu.stat
✅ 推荐
- 用 cgroups v2
- 通过 systemd 管理
- 设置 pids.max
- 设置 memory.high + memory.max
❌ 雷区
- v1/v2 混用
- memory.max 不留余量
- 忽略 swap 行为
- 容器无限 fork
| 维度 | Namespace | cgroups |
|---|---|---|
| 作用 | 隔离 | 限制 |
| 粒度 | 视图 | 配额 |
| 是否限制资源 | ❌ | ✅ |
| 容器必需 | ✅ | ✅ |
Namespace 决定世界的边界
cgroups 决定资源的上限