欢迎光临
我们一直在努力

Docker Compose 如何限制 CPU 和内存?容器资源限制教程

1. 为什么要限制 Docker 容器资源?

一台 Linux 服务器上通常不只运行一个 Docker 容器。

例如可能同时存在:

Nginx;

MySQL;

Redis;

WordPress;

监控面板;

下载服务;

后台任务。

如果其中一个容器突然出现异常,占满 CPU 或内存,就可能影响整台服务器上的其他业务。

例如某个容器:

CPU 长时间达到很高水平;

内存不断增长;

出现内存泄漏;

Java 堆配置过大;

数据库缓存占用过多;

异常任务不断执行。

最终可能导致:

服务器 SSH 卡顿;

其他容器响应变慢;

MySQL 被 OOM Killer 终止;

网站出现 502;

Docker 容器频繁重启。

因此对于一台运行多个服务的服务器,可以根据业务实际情况给部分容器设置合理的 CPU 和内存限制。

2. 先查看容器当前资源占用

Docker stats查看容器CPU和内存资源占用

执行:

docker stats

可以实时查看所有运行中的容器。

如果只想查看一次:

docker stats --no-stream

可能看到类似:

CONTAINER   CPU %   MEM USAGE / LIMIT    MEM %
web         78.4%   412MiB / 1GiB        40.2%
mysql       34.8%   1.72GiB / 2GiB       86.0%

重点可以关注:

CPU %

MEM USAGE / LIMIT

MEM %

BLOCK I/O

如果某个容器长期占用大量资源,再考虑是否需要限制。

不要看到某一次 CPU 突然升高,就立即设置非常严格的资源限制。

短时间高负载有时只是正常业务行为。

3. Docker Compose 限制 CPU

在 Compose 中,可以为服务配置:

cpus: 1.50

例如:

services:
  web:
    image: example/app:latest
    restart: unless-stopped
    cpus: 1.50

这里:

1.50

表示该容器能够使用的 CPU 计算资源受到相应限制。

它并不是把容器固定绑定到某一个 CPU 核心。

如果服务器有多个 CPU 核心,Docker 会根据限制调度容器能够使用的 CPU 时间。

修改 Compose 后重新部署:

docker compose up -d

如果需要确保容器使用新的资源配置:

docker compose up -d --force-recreate

4. 1 核服务器可以设置 cpus: 2 吗?

不建议这样配置。

容器能够使用的资源最终仍然受到宿主机实际 CPU 能力限制。

如果服务器本身只有:

1 核

那么设置:

cpus: 2

并不会凭空产生第二个物理或虚拟 CPU。

因此资源限制应该结合服务器实际配置。

例如 4 核服务器运行多个应用时,可以根据业务情况限制某个普通 Web 容器最多使用:

cpus: 1.50

而数据库则预留更多资源。

5. CPU 限制太低会发生什么?

如果将某个需要大量计算的程序限制得过低,可能出现:

网站响应变慢;

任务处理时间增加;

PHP 请求堆积;

Java GC 压力增加;

视频转码变慢;

后台任务执行时间明显延长。

所以 CPU 限制的作用不是:

让容器占用越低越好。

而是避免单个服务异常时无限争抢整台服务器资源。

应该根据正常业务峰值预留足够空间。

6. Docker Compose 限制内存

可以使用:

mem_limit: 1g

例如:

services:
  web:
    image: example/app:latest
    restart: unless-stopped
    mem_limit: 1g

表示为这个容器设置约 1GB 的内存上限。

配置完成以后重新创建容器:

docker compose up -d --force-recreate

然后执行:

docker stats --no-stream

可以看到类似:

412MiB / 1GiB

说明当前容器内存限制已经生效。

7. mem_limit 应该设置多大?

没有固定标准。

应该结合:

应用类型;

平时内存占用;

高峰期内存占用;

服务器总内存;

同机运行的其他容器。

例如一个轻量 Web 应用平时只使用:

200MB

高峰期可能达到:

500MB

那么直接限制成:

mem_limit: 256m

就可能过小。

更合理的方式是先通过:

docker stats

观察一段时间。

确认实际高峰以后,再保留一定余量。

8. mem_reservation 是什么?

除了硬限制,还可以设置:

mem_reservation: 512m

例如:

services:
  web:
    image: example/app:latest
    mem_limit: 1g
    mem_reservation: 512m

这里:

mem_limit

是更明确的内存上限。

mem_reservation

更偏向内存软预留或资源调度参考。

它不是“容器永远固定占用 512MB”。

也不代表系统一定会专门预留一块完全不能被其他程序使用的内存。

对于普通单机 Docker Compose 使用场景,真正防止容器无限吃内存的核心仍然是:

mem_limit

9. CPU 和内存一起限制

Docker Compose限制容器CPU和内存

比较常见的 Compose 配置可以写成:

services:
  web:
    image: example/app:latest
    restart: unless-stopped
    cpus: 1.50
    mem_limit: 1g
    mem_reservation: 512m

这样可以同时控制 CPU 和内存。

启动:

docker compose up -d

检查:

docker compose ps

再观察:

docker stats

确认项目运行是否正常。

10. 修改资源限制后为什么没有变化?

Compose 文件修改以后,已经运行的容器不一定立即使用新配置。

先执行:

docker compose config

确认 Compose 最终解析的配置正确。

然后:

docker compose up -d

如果仍然发现资源配置没有变化,可以执行:

docker compose up -d --force-recreate

重新创建容器。

之后再检查:

docker stats --no-stream

11. 如何确认 CPU 限制已经生效?

可以使用:

docker inspect 容器名称

也可以只查看 CPU 配置。

例如:

docker inspect -f '{{.HostConfig.NanoCpus}}' 容器名称

假设配置:

cpus: 1.50

可能看到类似:

1500000000

Docker 内部会使用对应的 CPU 限制参数保存配置。

普通用户不需要手工计算这个值。

主要用于确认容器是否已经应用新的限制。

12. 如何确认内存限制已经生效?

执行:

docker inspect -f '{{.HostConfig.Memory}}' 容器名称

例如 1GB 限制可能显示:

1073741824

这是按字节表示的值。

也可以直接通过:

docker stats

查看:

MEM USAGE / LIMIT

通常更加直观。

13. 内存限制太小会发生什么?

这是需要特别注意的地方。

假设容器正常运行需要:

800MB

但设置:

mem_limit: 512m

当应用尝试使用更多内存时,就可能出现内存压力。

严重情况下进程可能被终止。

随后如果 Compose 又设置了:

restart: unless-stopped

就可能出现:

程序被杀 → 容器退出 → Docker 自动重启 → 再次内存不足

最后表现成容器不断 Restarting。

所以资源限制过严本身也可能制造故障。

14. 如何检查容器是不是因为 OOM 被杀?

Docker检查容器资源限制和OOMKilled状态

执行:

docker inspect -f '{{.State.OOMKilled}}' 容器名称

如果输出:

true

说明这个容器曾经因为内存不足触发 OOM。

还可以查看退出码:

docker inspect -f '{{.State.ExitCode}}' 容器名称

以及服务器日志:

dmesg -T | grep -Ei 'oom|out of memory|killed process'

如果同时看到 OOM 相关日志,就应该重点检查:

容器内存限制是否过低;

服务器本身是否内存不足;

程序是否存在内存泄漏。

15. ExitCode 137 一定是 OOM 吗?

不一定。

137 通常表示进程收到了强制终止信号。

OOM Killer 是比较常见的一种原因,但不是唯一可能。

因此不要只看到:

ExitCode 137

就直接判断:

“服务器内存不够”。

应该继续检查:

docker inspect -f '{{.State.OOMKilled}}' 容器名称

以及:

dmesg -T | grep -Ei 'oom|killed process'

再判断是否确实属于 OOM。

16. Java 容器特别需要注意内存限制

Java 应用通常还有自己的 JVM 堆内存设置。

例如:

-Xmx2g

表示 Java 最大堆内存可能配置为约 2GB。

但如果 Docker 同时设置:

mem_limit: 1g

就会出现明显冲突。

容器总内存只有 1GB,但 Java 试图使用更大的堆空间,很容易导致应用异常。

因此 Java 项目应该同时考虑:

Docker 内存限制;

JVM Xmx;

JVM 非堆内存;

线程栈;

系统开销。

不要只调整其中一个参数。

17. MySQL 容器应该限制内存吗?

可以,但需要比较谨慎。

MySQL 会利用内存进行:

Buffer Pool;

连接;

排序;

缓存;

临时操作。

如果限制过低,可能出现:

数据库性能下降;

大量磁盘 I/O;

连接失败;

OOM。

因此数据库容器通常不适合直接套用 Web 容器的内存限制。

例如一个普通 Web 容器使用:

mem_limit: 512m

并不代表 MySQL 也适合 512MB。

应该根据:

数据库规模;

连接数量;

InnoDB Buffer Pool;

服务器总内存

单独评估。

18. Redis 容器也要考虑应用自身限制

Redis 本身支持:

maxmemory

如果 Docker 层设置 1GB,而 Redis 自己允许无限增长,最终仍可能撞到容器内存上限。

更加稳妥的方式通常是:

Docker 设置总体上限;

Redis 自身设置合理的 maxmemory;

给系统和 Redis 运行开销保留余量。

类似的原则也适用于:

Java;

Elasticsearch;

数据库;

缓存系统。

19. mem_limit 和应用自身内存配置有什么区别?

Docker:

mem_limit: 1g

属于:

容器外层资源限制。

应用自己的参数,例如:

Java -Xmx

Redis maxmemory

MySQL Buffer Pool

属于:

应用内部资源管理。

两者不是同一个层次。

更合理的配置应该是:

应用内部限制 < Docker 容器硬限制

并留出一定运行余量。

否则应用刚达到内部设计上限之前,容器可能已经先被 OOM。

20. CPU 限制会不会影响数据库?

会。

数据库在:

复杂查询;

索引创建;

备份;

数据导入;

高并发;

期间都可能需要较多 CPU。

如果限制过低,可能出现:

查询变慢;

请求积压;

连接响应变慢。

所以数据库资源限制应该基于实际监控数据,而不是为了“防止占资源”随便设一个很小的数。

21. 应不应该给所有容器都限制资源?

不一定。

如果服务器上只运行一个业务,而且资源充足,可以不急着增加严格限制。

如果一台服务器运行很多项目,则更有必要避免:

某一个异常容器拖垮整台服务器。

比较适合设置资源限制的场景包括:

测试环境;

多用户服务器;

大量 Docker 项目;

容易出现异常任务的应用;

后台计算任务;

爬虫;

转码服务。

核心原则是:

限制要基于实际资源使用情况。

22. 如何找到长期资源占用趋势?

docker stats 是实时数据。

如果需要长期趋势,可以结合监控系统。

例如你之前部署的 Beszel 就可以用于观察:

CPU;

内存;

磁盘;

网络;

Docker 容器

随时间变化的资源情况。

短时间看起来正常的容器,有时可能每天固定时间出现资源峰值。

因此在设置限制之前,最好先观察一段时间,而不是只看一分钟数据。

23. CPU 100% 是不是一定异常?

不一定。

例如一个容器在执行:

压缩;

编译;

图片处理;

视频转码;

数据计算;

时,短时间 CPU 很高可能属于正常现象。

真正需要关注的是:

持续时间;

业务是否受影响;

其他容器是否被拖慢;

Load Average 是否异常;

任务完成后是否恢复。

如果 CPU 长期打满,并且影响整台服务器,再考虑优化程序或限制资源。

24. Docker 容器内存高是不是一定有问题?

也不一定。

例如:

数据库;

Java;

缓存系统

本身就会主动使用较多内存。

判断是否异常时,更应该观察:

内存是否持续上涨;

是否长期不释放;

是否接近容器限制;

是否发生 OOM;

业务是否出现异常。

不要只看到某个容器占用 70% 内存就立即重启。

25. 服务器本身也必须预留资源

假设一台服务器只有:

4GB 内存

如果配置:

容器 A:2GB;

容器 B:2GB;

容器 C:1GB;

并不意味着这样就一定安全。

因为宿主机本身还需要运行:

Linux 内核;

Docker daemon;

SSH;

日志;

系统服务;

文件缓存。

因此所有容器限制之和不应该完全等于甚至明显超过服务器可用资源,而完全不给宿主机留空间。

26. Docker Compose 配置示例

例如一台服务器运行一个普通 Web 应用:

services:
  web:
    image: example/app:latest
    container_name: web
    restart: unless-stopped
    cpus: 1.50
    mem_limit: 1g
    mem_reservation: 512m
    ports:
      - "8080:8080"

启动:

docker compose up -d

查看:

docker compose ps

再观察资源:

docker stats

如果应用运行稳定,再继续观察真实业务高峰期的数据。

27. 修改前建议先验证 Compose

执行:

docker compose config

如果 Compose 文件格式有问题,会在这里提示。

确认无误后:

docker compose up -d

如果资源限制没有应用到现有容器:

docker compose up -d --force-recreate

然后再次检查:

docker stats --no-stream

28. Docker 资源限制快速排查表

问题现象优先检查
单个容器 CPU 长期很高docker stats
容器内存持续增长应用内存、mem_limit
容器突然退出ExitCode、OOMKilled
容器不断 Restarting内存限制、应用日志
Java 容器 OOMDocker 内存与 JVM Xmx
MySQL 变得很慢内存限制、Buffer Pool、I/O
修改限制没生效是否重新创建容器
宿主机还是内存不足所有容器总占用
CPU 限制后应用变慢cpus 是否设置过低
内存限制后频繁崩溃mem_limit 是否过小

推荐按照:

docker stats → Compose配置 → docker inspect → OOM日志 → 应用自身资源配置

的顺序排查。

29. Docker 项目越来越多怎么办?

如果一台服务器上的 Compose 项目越来越多,可以使用 Dockge 统一管理 Stack。

相关阅读: 使用 Docker 搭建 Dockge:可视化管理 Docker Compose 项目

如果服务器还没有安装 Docker:

安装教程: 服务器上安装docker和docker-compose教程

如果需要搭建 Docker、数据库、WordPress、监控面板等项目,可以根据实际业务负载选择莱卡云 Linux 云服务器。

查看官网购买链接: https://www.lcayun.com

服务器配置选择时,不要只看容器数量。

真正应该考虑的是:

CPU 峰值;

内存峰值;

数据库规模;

磁盘 I/O;

网络流量。

30. 总结

Docker Compose 设置 CPU 和内存限制,可以降低单个异常容器影响整台服务器的风险。

首先建议使用:

docker stats

观察实际资源使用情况。

然后根据业务配置:

cpus: 1.50
mem_limit: 1g
mem_reservation: 512m

修改以后通过:

docker compose up -d --force-recreate

让容器使用新的配置。

如果容器频繁退出,还应该检查:

docker inspect -f '{{.State.OOMKilled}}' 容器名称

以及:

dmesg -T | grep -Ei 'oom|killed process'

判断是否发生内存不足。

资源限制不是越小越好。

正确的思路应该是:

先监控实际使用量 → 保留合理余量 → 设置限制 → 持续观察业务状态。

这样才能在保证应用正常运行的同时,避免某一个 Docker 容器占用过多服务器资源。

赞(0)
未经允许不得转载:莱卡云 » Docker Compose 如何限制 CPU 和内存?容器资源限制教程