最有效的是设硬性上限:内存需--memory与--memory-swap配合禁用swap,cpu用--cpus硬配额而非--cpu-shares权重,pid和磁盘io也须限制,且必须验证cgroup生效并持续监控。

直接设硬性上限是最有效的办法。cgroups 不是锦上添花的选项,而是生产环境必须开启的底线防护——不配限额,等于默认允许单个容器吃光宿主机所有 CPU、内存、进程数或磁盘 IO。
内存:必须同时限制物理内存和 swap 总量
只设 --memory=512m 是不够的。容器仍可大量使用 swap,导致磁盘 IO 暴涨、系统响应卡死。关键在 --memory-swap:
- --memory=512m --memory-swap=512m:彻底禁用 swap,只准用 512MB 物理内存(推荐)
- --memory=512m --memory-swap=1g:内存 + swap 合计不超过 1GB(即最多再用 512MB swap)
- --memory-swap=-1:允许无限 swap(生产环境严禁)
验证是否生效:docker inspect 容器名 | jq '.[0].HostConfig.MemorySwap'。若返回 -1 或空值,说明未启用限制。
CPU:用 --cpus 做硬配额,别依赖 --cpu-shares
--cpu-shares 只是权重,空闲时照样跑满全部 CPU。真正防止单容器霸占资源,得靠 --cpus:
- --cpus=1.2:每 100ms 最多占用 120ms CPU 时间(即硬性封顶 1.2 核)
- --cpuset-cpus="0-1":进一步绑定到特定物理核,减少跨 NUMA 访存开销
- Java 等应用还需同步调小 JVM 堆(如
-Xmx384m),否则堆外内存可能绕过 Docker 限制
PID 和磁盘 IO:常被忽略的两个致命点
fork 炸弹几秒就能耗尽系统 PID 数(默认通常 32768),导致新进程无法启动,整机假死:
- --pids-limit=128:该容器内最多运行 128 个进程/线程(含子线程)
- 禁止搭配
--pid=host或--privileged,否则限制完全失效
高吞吐服务(如数据库、对象存储)还应限制磁盘 IO,避免打满宿主机 I/O 队列:
- --device-read-bps=/dev/sda:30mb:从 sda 每秒最多读 30MB
- --device-write-iops=/dev/sda:150:向 sda 每秒最多写 150 次 IO
验证与持续监控不能少
配额不是“设完就完”。需实时确认是否生效并建立响应机制:
- 运行中检查:
docker stats 容器名查看实时 CPU、内存、IO 占用 - 确认 cgroup 生效:
cat /sys/fs/cgroup/pids.max(进容器执行)或cat /sys/fs/cgroup/memory.max(在宿主机查对应路径) - 接入 cAdvisor + Prometheus,对
container_memory_usage_bytes设告警(如持续超限 85% 达 90 秒) - 预设应急脚本:当某容器连续触发 OOMKilled 或 CPU 超限,自动执行
docker update --memory=256m 容器名降级或docker stop











