容器资源限制:CPU、内存与 OOM 的边界
一台小主机跑十几个容器,某个服务内存泄漏把整机拖死——这是不设限制的典型后果。
但限制设得太紧,又会出现「莫名被杀」:容器内存到 limit 就被 OOM killer 干掉,日志里什么都没有。
先说结论
内存 limit 要留出运行时开销,CPU 用 shares 做软限制。 Java/Node 必须开容器感知。
- 内存 limit 比应用峰值高 20%-30%
- CPU 用 --cpus 限制总量,shares 用于竞争分配
- 开启 swap 限制(--memory-swap)
- JVM 用 -XX:MaxRAMPercentage
先把问题说清楚
cgroups v2 下内存超限直接触发 OOM kill,容器退出码 137,日志里通常看不到原因。
CPU 的 --cpus 是硬限额(按周期分配),--cpu-shares 是相对权重,只在竞争时生效。
具体怎么做
按顺序执行,每步都验证完再进下一步:
- 先观察一周真实峰值(docker stats / cAdvisor)
- 按峰值 + 30% 设内存 limit
- CPU 设 --cpus,多服务竞争时再调 shares
- Java/Node/Python 显式设置堆上限,识别 cgroup 限制
- 监控 OOM 事件(dmesg 与容器退出码 137)
参数与成本对照
把关键数值摊开,方便判断该选哪条路:
| 资源 | 参数 | 行为 |
|---|---|---|
| 内存 | --memory | 超限触发 OOM kill |
| swap | --memory-swap | 控制可换出量 |
| CPU | --cpus | 按周期硬限 |
| CPU | --cpu-shares | 竞争时按权重分配 |

几个容易踩的坑
下面这些是最常见的错误做法:
- 只看平均内存不看峰值:突发流量直接 OOM
- JVM 不设 MaxRAMPercentage:堆按宿主机内存算,必超
- 限制 CPU 到 0.1 核:启动都困难
- 忽略页缓存:文件读写多的容器内存统计偏高
最后补两句
资源限制的前提是「知道正常水位」。先观察,再设限,最后加告警。
工具是手段,理解机制才是能力。命令记不住没关系,知道「该看什么」就够了。
评论 (3)
照着做了一遍,确实少走弯路。第二步最容易漏,建议顺手加个检查清单。
比「一键脚本」有用多了,知道为什么比知道怎么做重要。
补充一句:不同版本行为会变,动手前先确认自己的版本号。
发表评论