容器资源限制防止抢占内存宕机:容器资源限制实战
你的服务器为什么总在晚上突然挂掉?
如果你在用 Docker 跑多个容器,
管理员最怕的场景就是:
某个容器因为代码 bug 或内存泄漏,
把宿主机所有内存吃光,
然后其他容器连带系统一起崩掉。容器资源限制就是用来解决这个问题的——给每个容器设定一个最高内存和 CPU 上限,
一旦超过,
系统自动杀掉越界的进程(OOM kill),
而不是拖垮整台机器。
本文会带零基础用户实操:从安装 Docker、启动容器时加限制,到修改已有容器的配额,再到验证效果和排错。
全程命令可直接复制执行。
动手设置容器内存上限
1. 运行新容器时直接限制
使用 --memory 参数指定最大内存,单位可以用 b(字节)、k、m、g。
下面启动一个 Nginx 容器,给它 512 MB 内存上限:
docker run -d --name web-nginx --memory=512m nginx:latest
注意: 如果你不限制 swap,容器可能会通过 swap 绕过内存限制。
更严格的做法是同时限制 swap:
docker run -d --name web-nginx --memory=512m --memory-swap=512m nginx:latest
--memory-swap 等于 --memory 时表示完全禁用 swap,超出 512 MB 直接 OOM。
2. 限制已运行容器的资源
假如容器已经在跑,不想重启,用 docker update 动态调整:
docker update --memory 512m web-nginx
如果要同时关掉 swap,也得设置 --memory-swap:
docker update --memory 512m --memory-swap 512m web-nginx
docker update 只对 restart=always 或正在运行的容器生效,重启后依然保留设置。
CPU 配额也要管住
光限制内存不够,一个容器还能吃满所有 CPU 核心。
给 CPU 加上限:
docker run -d --name web-nginx --cpus=1.5 nginx:latest
--cpus 后面的数字表示容器最多可以使用的 CPU 核心数(例如 1.5 核)。
如果宿主是 4 核,设 --cpus=2 就是最多用一半。
对已有容器更新 CPU:
docker update --cpus 1.5 web-nginx
配合作战: 建议每个容器同时设 --memory 和 --cpus,防止单一维度被打满。
这些坑我已经帮你踩过了
1. 单位写错导致限制失效
--memory=512 不写单位,会被当成 512 字节,等于没限制。
必须写 512m 或 512M(M 大小写均可)。
2. 忘记关 swap
默认情况下 Docker 允许容器使用和内存等量的 swap。
如果只设 --memory=1g,容器有可能吃到 2g(内存+swap)才被 kill。
建议在 production 环境显式设置 --memory-swap 与 --memory 相同,彻底关掉 swap 绕过。
3. 限制太小导致容器频繁重启
如果应用本身需要 1GB 内存,你却只给 512MB,容器会因为 OOM 被反复杀死。
先用 docker stats 观察正常运行时峰值内存,然后在此基础上加 20%-30% 缓冲。
4. docker update 不支持所有资源类型
CPU 和内存可以用 update 调整,但某些高级限制(如 --blkio-weight)不支持动态修改,需要重建容器。
怎么确认限制生效了?
方法一:实时监控
docker stats
输出中会显示每个容器的 MEM USAGE / LIMIT 和 CPU %。
如果 LIMIT 列显示你设的值(例如 512MiB),说明限制已生效。
方法二:压力测试
进容器执行一个吃内存的程序(仅测试用,注意安全):
docker exec -it web-nginx /bin/bash
# 安装 stress 工具(Debian/Ubuntu)
apt update && apt install -y stress
stress --vm 1 --vm-bytes 600M --timeout 10s
几秒后容器应该因为 OOM 被强制退出(docker ps 看不到进程,docker ps -a 显示 Exited 137)。
这证明限制生效了。
常见疑问速答
Q:限制会影响性能吗?
A:只要给独享资源(比如分配 4 核中的 2 核),性能几乎没有损失。反倒是资源不受控时频繁 OOM 才影响性能。
Q:容器重启后限制会消失吗?
A:不会。docker run 时设置的参数会写入容器配置;docker update 修改后也立即生效,重启容器保留。
Q:已经跑起来的容器没限制,怎么批量加上?
A:先用 docker ps --format "table {{.ID}} {{.Names}}" 列出所有容器,再用 docker update 逐条执行。也可以用脚本循环:
for c in $(docker ps -q); do docker update --memory 512m --cpus 1 $c; done
注意这个命令对所有运行容器统一设值,建议先逐个判断应用需求。
总结
给 Docker 容器加上资源限制是防止服务器因单个应用出问题而整体瘫掉的第一道防线。
记住三步:启动时用 --memory 和 --cpus,运行时用 docker update,最后用 docker stats 验证。
遇到异常内存占用,先检查限制值是否合理,再排查应用本身。
如果你正在配置多个容器的资源配额,建议先按本文步骤在测试环境走一遍所有命令,确认无误后再上生产。
遇到 OOM 异常时,优先回头检查 --memory-swap 的设置。