容器资源限制:通过 cgroups 实现 CPU 与内存隔离

作者:袖梨 2026-07-03
容器资源限制的核心在于Linux内核的cgroups机制,而非Docker自带功能;它通过cpu、memory等子系统实现CPU时间配额(cfs_quota_us/cfs_period_us)、相对权重(cpu.shares)、内存硬上限(memory.limit_in_bytes)及swap协同控制,并需区分cgroups v1/v2配置路径与接口。

容器资源限制的核心在于 cgroups,它不是 Docker 或 rkt 自带的功能,而是 Linux 内核提供的底层机制。CPU 和内存隔离不是“开关式”操作,而是通过配置特定子系统的接口文件来实现的——关键在于理解每个参数的实际含义和生效条件。

CPU 隔离:两种方式,用途完全不同

CPU 控制分两类:一种是硬性时间配额,一种是相对权重分配,二者不能混用。

  • 硬性限制(推荐用于生产):用 cpu.cfs_quota_uscpu.cfs_period_us 组合控制实际可用 CPU 时间。例如设 period=100000μs(即 100ms),quota=50000μs,就表示该 cgroup 每 100ms 最多运行 50ms,等效于 50% 的单核利用率。Docker 的 --cpus="0.5" 就是自动算出这个组合并写入。
  • 权重分配(适合多容器共存场景):用 cpu.shares 设置相对份额,默认 1024。若 A 设为 2048、B 设为 1024,当两者同时争抢 CPU 时,A 获得约 2/3 时间,B 约 1/3;但若只有 B 运行,它仍可用满全部 CPU。Docker 的 --cpu-shares 直接映射此值。
  • 绑定物理核心(提升确定性):通过 cpuset.cpus 指定允许使用的 CPU 编号,比如 "0-1""0,2"。这对实时性要求高的服务(如音视频转码)很关键,也能避免跨核缓存失效带来的性能抖动。

内存隔离:上限与交换必须协同设置

内存限制看似简单,但只设 --memory 很可能引发意外 OOM,因为内核默认允许使用等量 swap。真正可控的内存上限由两个值共同决定:

  • 硬上限:通过 memory.limit_in_bytes(Docker 的 --memory)设定。一旦进程组总内存使用(含 page cache)超过该值,内核 OOM Killer 会按评分规则杀掉其中某个进程。
  • swap 总量memory.memsw.limit_in_bytes 是内存 + swap 的总上限。Docker 中用 --memory-swap 控制,且必须 ≥ --memory。若设 --memory=512m --memory-swap=1g,表示最多用 512MB 物理内存 + 512MB swap;若设 --memory-swap=-1,则不限 swap(不推荐)。
  • 注意 soft limit:cgroups v1 支持 memory.soft_limit_in_bytes,但仅在内存紧张时起作用,实际生产中极少使用;v2 已移除该字段,统一用压力反馈机制替代。

cgroups 版本差异直接影响配置方式

当前主流系统大多已启用 cgroups v2,但它和 v1 的路径、文件名、逻辑都不同,混用会导致配置无效。

  • v1 是多挂载点/sys/fs/cgroup/cpu//sys/fs/cgroup/memory/ 各自独立,可分别挂载、分别控制。
  • v2 是单一层级:所有控制器统一挂载在 /sys/fs/cgroup/ 下,一个目录同时控制 CPU、内存、IO 等。需先启用 unified hierarchy(通常 systemd 默认开启),再用 memory.maxcpu.max 等新接口文件。
  • 检查当前模式:运行 stat /sys/fs/cgroup | grep Type,若显示 cgroup2 即为 v2;或直接看 /sys/fs/cgroup/cgroup.controllers 是否存在。

验证是否生效:别只看命令参数

容器启动后,不能只信 docker inspect 输出,要进 cgroup 目录查真实值。

  • 找到容器对应 cgroup 路径:Docker 通常在 /sys/fs/cgroup/cpu/docker/<container-id>(v1)或 /sys/fs/cgroup/docker/<container-id>(v2)
  • 读取关键文件:cat cpu.max(v2)或 cat cpu.cfs_quota_us(v1)确认 CPU 配置;cat memory.maxcat memory.limit_in_bytes 确认内存上限。
  • 观察实时使用:cat cpu.stat 查已用时间,cat memory.current 查当前内存占用,比容器内 top 更准确。

相关文章

精彩推荐