4. 内存限制:使用 -m/--memory 参数限制容器内存
内存限制,说白了就是给容器划个“内存红线”。
我刚开始用 Docker 的时候,觉得这玩意儿可有可无。直到有一次线上服务突然 OOM,把宿主机整挂了……嗯,从那以后我再也不敢不设内存限制了。
4.1 为什么需要限制容器内存?
你想想看,一个容器如果不设内存上限,它就能把宿主机的内存吃光。Docker 默认是不限制的,这其实挺危险的。
我在项目中遇到过这样的情况:某个 Java 应用的内存泄漏,直接把 32G 的机器干到 Swap 爆满,最后所有容器都跟着遭殃。所以,内存限制不是“锦上添花”,而是“保命手段”。
4.2 基本用法:-m 或 --memory
最简单的用法,就是指定一个硬限制:
docker run -m 512m nginx
这条命令的意思是:这个 nginx 容器最多能用 512MB 内存。超过了怎么办?会被 OOM Kill。
我个人习惯用这些单位:
- b:字节(不常用)
- k:千字节
- m:兆字节(最常用)
- g:吉字节
举个例子:
docker run -m 1g --name myapp myapp:latest
这表示容器最多用 1GB 内存。超过就杀。
4.3 内存限制 + Swap 限制:--memory-swap
光设 -m 还不够。我建议你同时控制 Swap。
为什么要控制 Swap?因为 Swap 用多了,性能会急剧下降。我曾经排查过一个“慢查询”问题,最后发现是容器疯狂用 Swap,磁盘 I/O 爆了。
语法是这样的:
docker run -m 512m --memory-swap 512m nginx
这表示:物理内存 512MB,Swap 为 0。也就是说,容器最多只能用 512MB,超了就杀,绝不给你用磁盘当内存的机会。
如果你想给一点 Swap 空间:
docker run -m 512m --memory-swap 768m nginx
这表示:物理内存 512MB,Swap 256MB(768 - 512 = 256)。
| 参数组合 | 物理内存 | Swap | 总可用 |
|---|---|---|---|
| -m 512m | 512MB | 512MB(默认) | 1GB |
| -m 512m --memory-swap 512m | 512MB | 0 | 512MB |
| -m 512m --memory-swap 768m | 512MB | 256MB | 768MB |
| -m 512m --memory-swap -1 | 512MB | 无限制 | 无限制 |
4.4 内存软限制:--memory-reservation
这个参数很多人不知道。它是个“软限制”。
什么意思呢?就是当宿主机内存充足时,容器可以用超过这个值的内存。但当宿主机内存紧张时,Docker 会尽量把容器内存压到软限制以下。
举个例子:
docker run -m 1g --memory-reservation 512m nginx
这表示:
- 硬限制 1GB(不能超过)
- 软限制 512MB(尽量不超过)
我一般在部署多个容器时用这个参数。比如一台机器跑 10 个容器,每个软限制 512MB,硬限制 1GB。平时大家用 512MB 左右,某个容器突然需要更多内存时,可以临时“借”一点。但谁也别想超过 1GB。
- -m / --memory:硬限制,超过就杀
- --memory-reservation:软限制,尽量遵守
4.5 查看内存使用情况
设了限制之后,怎么知道容器用了多少内存?
我最常用的命令:
docker stats
这个命令会实时显示所有容器的 CPU、内存、网络 I/O 等信息。输出大概长这样:
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O
abc123 myapp 0.50% 256MiB / 512MiB 50.00% 1.2kB / 0B
看到 MEM USAGE / LIMIT 那列了吗?256MiB / 512MiB 表示用了 256MB,限制是 512MB。
如果你想看更详细的内存信息:
docker inspect myapp | grep -i memory
或者直接进容器看:
docker exec myapp cat /sys/fs/cgroup/memory/memory.limit_in_bytes
这个文件里存的就是内存限制的字节数。536870912 就是 512MB。
4.6 实战中的避坑指南
我踩过不少坑,分享几个给你:
- 别把 -m 设得太小:比如 Java 应用,JVM 本身就要占不少内存。设得太小,容器刚启动就被杀了。我一般会留 20%-30% 的余量。
- 注意 --memory-swap 的默认行为:如果不显式设置,Docker 会让 Swap 等于内存。这可能导致容器实际可用内存比你设的大一倍。
- OOM 优先级:Docker 会调整容器的 OOM 优先级。但如果你手动设了 --oom-kill-disable,容器就不会被 OOM Kill,而是卡住。这通常不是好主意。
4.7 总结一下
内存限制这事儿,说白了就三点:
- 用 -m 设硬限制,防止容器吃光宿主机内存
- 用 --memory-swap 控制 Swap,避免性能下降
- 用 --memory-reservation 设软限制,让资源分配更灵活
我个人习惯是:生产环境一律设 -m 和 --memory-swap 相等,再根据压测结果定一个合理的软限制。这样既安全,又不会浪费资源。
嗯,下一章我们聊聊 CPU 限制。那个比内存限制稍微复杂一点,但原理是相通的。