容器的内存与 CPU 限制
如何为容器设置内存和 CPU 上限、为什么没有限制时一个服务会拖垮其他所有服务,以及如何判断进程是被内核杀掉的。
更新于 2026年8月23日
默认情况下,一个容器可以占用机器上的全部内存和所有核心。在 2 GB 的 VDS-1 上,结果可想而知:某个服务膨胀,内核开始杀进程,而倒下的不是它,是旁边的数据库。
如何设置上限
services:
app:
image: ghcr.io/example/app:1.5.0
deploy:
resources:
limits:
memory: 768M
cpus: "1.0"
reservations:
memory: 256M
即使只是执行普通的 docker compose up -d,Compose 也会应用 deploy.resources.limits。docker run 的等效写法:
docker run -d --memory 768m --cpus 1.0 --memory-swap 768m <image>
将 --memory-swap 设为与 --memory 相等可以禁止交换:干脆地崩溃,总好过机器几个小时几乎动不了。
应该分配多少
从您的套餐出发,给系统留一些余量。
| 套餐 | 内存 | 合理的容器总上限 |
|---|---|---|
| VDS-1 | 2 GB | 最高 1.5 GB |
| VDS-2 | 4 GB | 最高 3 GB |
| VDS-3 | 8 GB | 最高 6.5 GB |
| VDS-4 | 16 GB | 最高 14 GB |
| VDS-5 | 24 GB | 最高 21 GB |
| VDS-6 | 32 GB | 最高 29 GB |
剩下的部分要留给系统、文件缓存和 Docker 本身。各上限之和超过内存总量不是配置失误——而是一场迟早发生的灾难。
关于 CPU:cpus: "1.0" 表示一个完整核心。VDS-1 只有一个核心,在那里限制 CPU 意义不大,但在 VDS-4 及以上,值得避免服务器配置占满全部六个核心。
实际消耗了多少
docker stats --no-stream
docker stats --no-stream --format "table {{.Name}}\t{{.MemUsage}}\t{{.CPUPerc}}"
free -h
在负载下观察服务一天,然后把上限设为峰值的大约一倍半。上限设得太紧比不设更糟:服务会在您最需要它的时候重启。
全屏的
htop和btop只在“Screen”控制台(VNC)中可用。文本控制台不传递窗口尺寸,那里始终是 80×24,界面会错乱。要在文本控制台中快速测量,请使用docker stats --no-stream和free -h。
如何判断是被内存杀掉的
docker inspect -f '{{.State.ExitCode}} {{.State.OOMKilled}}' <container>
sudo dmesg -T | grep -i -E "out of memory|killed process"
退出码 137 加上 OOMKilled: true 就是明确的判决。接下来您有两个选择:如果上限设得太低就调高,或者弄清楚应用为什么持续增长——内存泄漏不会因为加内存而治愈,只会被推迟。
Java 及其他特殊情况
Java 虚拟机有时看到的仍是宿主机的内存,而不是容器上限,并据此按并不存在的余量来设置堆大小。请显式指定:
environment:
JAVA_TOOL_OPTIONS: "-Xmx512m -Xms256m"
PostgreSQL(shared_buffers)以及任何带有自己的连接池的服务也是如此。