docker容器限制内存

问题

当你使用 docker run --memory=10240m 启动容器时,理论上应该限制容器最多使用约 10GB 的内存。然而,如果你发现:

  • docker stats 显示容器可以使用宿主机全部内存;

env

  • centos7.9
  • docker cgroupv1

分析

1. 使用 --network host 时,未开启 cgroup v2 或宿主机未正确配置 cgroups

检查是否为 cgroup v1 或 v2:

1
mount | grep cgroup
  • 如果你看到 cgroup2,说明是 v2。
  • 如果是传统的 cgroup(v1),部分内存限制在某些系统(尤其是老版本内核或某些发行版)不生效。

推荐使用 cgroup v2 + systemd 管理资源限制,可以在现代 Linux(如 Ubuntu 20.04+/Debian 11+/CentOS 8+/Arch)中生效。


2. 启动容器的 Docker Daemon 没有正确启用内存限制功能

检查 docker info 输出中是否包含如下内容:

1
docker info | grep -i cgroup

应看到:

Cgroup Driver: systemd
Cgroup Version: 2   # or 1, 但要正确挂载 memory 子系统

若未启用限制,请检查内核参数:

编辑 /etc/default/grub 添加内核参数(仅限 grub 系统):

1
GRUB_CMDLINE_LINUX="... systemd.unified_cgroup_hierarchy=1 cgroup_enable=memory swapaccount=1"

然后执行:

1
2
sudo update-grub
sudo reboot

3. 使用 --network=host 时,容器与宿主共享网络命名空间,不影响内存限制

这是很多人误会的点:**--network host 不会破坏 cgroup 限制!**


4. docker stats 显示的是 “宿主内存总量”,并不代表限制失效

示例解释:

1
2
3
docker stats
CONTAINER ID NAME MEM USAGE / LIMIT ...
ab12345cde web 200MiB / 15GiB ...

此处的 15GiB 可能是宿主机总内存,并不代表容器能用 15GB。

正确查看内存限制:

1
2
3
cat /sys/fs/cgroup/memory/memory.limit_in_bytes
# 或 cgroup v2:
cat /sys/fs/cgroup/memory.max

在容器内执行也可以验证限制是否生效。


2.调整 run 命令为

1
2
3
4
5
6
7
docker run \
--name mycontainer \
--network host \
--restart always \
--memory 10240m \
--memory-swap 10240m \ # 限制 swap 和内存总和
myimage

其中 --memory-swap 默认值是内存限制的两倍,必须手动指定为与 --memory 相同,否则容器还是可能多用一些 swap。


3.验证是否生效

容器内执行:

1
2
cat /sys/fs/cgroup/*/memory.max
cat /sys/fs/cgroup/*/memory.swap.max

应看到限制为 10G。


4.附加建议

  1. docker stats 只是参考,不能当作内存限制的唯一验证工具
  2. 如在 K8s 中部署,建议使用 resources.limits.memory 来限制。
  3. 不要在 run 时挂载宿主机的 cgroup 路径,避免绕过限制。