最可靠的方式是启用cgroups v2并设memory.max禁用swap:需验证mount输出cgroup2、/sys/fs/cgroup/cgroup.controllers存在,配置grub参数并重启;docker须设--memory=512m --memory-swap=512m,并通过/sys/fs/cgroup/docker/xxx/memory.max与memory.swap.max双重确认。
最可靠的方式是用 cgroups v2 设置 memory.max 并禁用 swap,同时确保限制在容器生命周期内持续生效。只靠 docker 启动参数不够,必须验证底层 cgroup 状态是否真实写入。
必须启用 cgroups v2 并确认挂载
cgroups v1 多挂载点、行为不一致,容易漏控;v2 是统一单层级,生产环境唯一推荐:
- 运行 mount | grep cgroup2,看到 cgroup2 on /sys/fs/cgroup type cgroup2 才算正常
- 检查 /sys/fs/cgroup/cgroup.controllers 是否存在且非空(v1 下该路径不存在)
- 若未启用:编辑 /etc/default/grub,在 GRUB_CMDLINE_LINUX 中追加 cgroup_no_v1=all systemd.unified_cgroup_hierarchy=1,再执行 sudo update-grub && sudo reboot
设硬性物理内存上限(禁用 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 或空值,说明未启用限制。
绕过 Docker 的直接验证方式
Docker inspect 只显示启动参数,不能反映实时 cgroup 状态。必须查原始 sysfs:
- 查出容器主进程 PID:docker inspect -f '{{.State.Pid}}' 容器名
- 定位其 cgroup 路径:cat /proc/$PID/cgroup,找到类似 0::/docker/xxx 的行
- 进入对应路径,例如:cat /sys/fs/cgroup/docker/xxx/memory.max —— 应显示 536870912(即 512MB)
- 同时检查:cat /sys/fs/cgroup/docker/xxx/memory.swap.max,应等于 memory.max 值(表示 swap 已禁用)
生产环境建议补充项
防止配置漂移或重启失效:
- Java 等应用需同步调小 JVM 堆,如 -Xmx384m,否则堆外内存可能绕过 Docker 限制
- 监控关键指标:container_memory_usage_bytes 持续超限 85% 达 90 秒时触发告警
- 预设应急脚本:当某容器连续触发 OOMKilled,自动执行 docker update --memory=256m 容器名 降级











