Skip to content
VDS · Docker 与容器

容器的内存与 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-12 GB最高 1.5 GB
VDS-24 GB最高 3 GB
VDS-38 GB最高 6.5 GB
VDS-416 GB最高 14 GB
VDS-524 GB最高 21 GB
VDS-632 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)以及任何带有自己的连接池的服务也是如此。

常见错误

  • 完全没有设置上限。 “机器卡死,毫无响应”最常见的原因。
  • 设了上限,但没有健康检查。 容器被杀掉后再也没有重启。请添加 restart: unless-stopped 和 healthcheck——参见更新容器。
  • 忘了磁盘。 您限制了内存,但写入会撞上另一道天花板:参见磁盘速度。