先记住这个答案
--cpu-shares 默认 1024,表示容器 CPU 权重,只在系统 CPU 时间不足时按比例分配,CPU 空闲时不限制使用量。--cpus 则通过设置 CFS quota 直接限制容器在一个周期内最多使用的 CPU 时间,是硬上限,即使其他容器空闲也不能超过该值。两者可同时使用,但语义不同。
- cpu-shares 仅争抢时按权重比例分配
- cpus 是硬上限,超出即被节流
- 空闲时 shares 不限制,cpus 仍限制
权重与配额的内核语义
内核 CFS 调度器为每个 cgroup 维护调度周期 cpu.cfs_period_us,默认 100000 微秒(100ms)。--cpus 会设置 cpu.cfs_quota_us,例如 --cpus=1.5 等价于 quota 150000,即容器在每个周期最多只能运行 1.5 个 CPU 时间,超出的线程会被节流(throttled)。这是硬限制,与系统其他负载无关。
--cpu-shares 则写入 cpu.shares,是容器在争抢时的权重。当多个容器同时需要 CPU 时,内核按权重比例分配可用时间片。若容器 A 的 shares 为 2048,B 为 1024,则 A 获得 B 的两倍 CPU 时间。但若 CPU 空闲,某容器可自由使用全部核心,甚至超过其权重对应的份额。
实际部署中的选择案例
假设宿主机有 4 核。若只设 --cpu-shares:容器 X 设 2048,Y 设 1024,当 CPU 空闲时,两者都可不限地使用任意核心;当两者同时满负载运行时,内核按权重分配,X 获得约 2/3 的可用 CPU 周期,Y 获得 1/3。若设 --cpus=2,则无论系统负载如何,X 最多只能使用 2 核,即使 Y 不设限制并占满其他核心,X 的用量也不会超过 2 核。
实际部署中,若给关键服务与后台任务都设 --cpus=1,两者各自有 1 核上限,当物理核足够(如≥2)时不会争抢,shares 不参与;当物理核不足(如仅 1 核)时,两者合计可能超过物理能力,内核会根据 shares 权重分配时间,高 shares 的服务获得更多 CPU 时间。此时,--cpus 仍限制每个容器在未争抢时的最大使用量,但实际可用量受物理资源制约。
适用边界与失效条件
--cpu-shares 仅在系统 CPU 时间不足(争抢)时生效,若宿主机只有该容器运行,则 shares 无实际作用,因为容器可按需使用所有 CPU。shares 不保证最小或最大资源,只影响调度器在争抢时按权重分配可用 CPU 时间的比例。
--cpus 的硬上限由内核的 CFS quota 机制实现,在 cgroup v1 和 v2 下均有效。若容器内线程频繁睡眠,实际消耗的 CPU 时间可能低于 quota,但 quota 仍然是硬性上限。注意,若物理 CPU 核数少于 quota 对应的核数(如 1 核机器设置 --cpus=2),容器不会因 quota 被节流,因为它无法实际使用超过物理能力的 CPU 时间;quota 只是规定了上限,实际性能仍受物理核数限制。
容易答错的地方
- 把 shares 当硬限制
- 误以为设置
--cpu-shares=512就限制容器最多使用半个 CPU。实际是权重,空闲时可使用任意多 CPU,只有争抢时按比例分配,且没有最大值保障。 - 认为 cpus 和 shares 互斥
- 有人以为只能用一个,实际上可同时设置。此时
--cpus定义绝对上限,--cpu-shares在争抢时调整相对优先级,但 share 不会增加或减少 cpus 的上限。
面试官还会怎么问?
如果两个容器都设了 --cpus=1,但一个 shares 高,另一个低,满载时行为如何?
两个容器都有 --cpus=1,CPU 上限均为 1 核。若物理核数 ≥2,两者可并行执行,不会争抢,shares 不生效。若物理核数 <2(如只有 1 核),则会发生争抢,但由于两者 quota 均为 1 核,各自单周期内最多使用 1 核的 CPU 时间,而物理资源总量不足,调度器会根据 shares 权重分配可用时间,高 shares 的容器将获得更多时间。因此,shares 在争抢时影响分配比例,而非仅调度顺序。
如何验证 --cpus 限制是否生效?
在宿主机上,找到该容器对应的 cgroup 文件(如 /sys/fs/cgroup/cpu/docker/<id>/cpu.cfs_quota_us),其值应等于所设 --cpus 值乘以 cpu.cfs_period_us(默认 100000 微秒),例如 --cpus=1.5 时该值应为 150000。在 cgroup v2 下,查看 cpu.max 文件,格式为 <quota> <period>,同样验证 quota/period 是否等于所设 --cpus。然后可用 stress 在容器内进行多线程压测,并在宿主机上用 docker stats 观察,容器的 CPU 使用率不应超过 --cpus 值对应的百分比(如 --cpus=1 时不超过 100%,--cpus=2 时不超过 200%)。
在 cgroup v2 上,这些限制如何表示?
cgroup v2 使用 cpu.max 文件,格式为 quota period,例如 100000 100000 表示 1 核。--cpus 和 --cpu-shares 仍由 Docker 转换为对应 cgroup v2 属性,但 cpu.shares 变成了 cpu.weight,范围 1-10000,默认 100。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。