### [Docker容器怎么限制CPU和内存?防止一个容器吃光VPS所有资源](https://www.jiyueip.com/article/13847) **Published:** 2026-08-01T04:02:01 **Author:** 斑斓 **Excerpt:** Docker容器默认可以使用VPS的全部CPU和内存,一个内存泄漏就能拖死整台机器。本文给出内存硬限制软限制、… 在VPS上跑Docker,最怕的局面不是服务挂了,是**一个容器的内存泄漏把整个机器拖死**——MySQL因为一个慢查询撑到2GB、Node.js的内存泄漏慢慢涨到1.5GB、Java应用的堆内存不受控制。默认情况下Docker容器可以使用宿主机的全部CPU和内存,一个出问题的容器可以吃掉所有资源,导致SSH都连不上。 本文给出Docker容器资源限制的完整配置方法:内存硬限制和软限制、CPU权重和绑定、重启策略和健康检查的配合使用。**[雨云](https://www.jiyueip.com/link/5617)优惠码admin01**新用户五折,KVM云服务器完整支持cgroup,资源限制配置可以精确生效。 ## 默认情况下Docker容器没有资源限制 用 `docker stats` 可以实时看到所有容器的资源占用: ``` docker stats --no-stream ``` 输出会显示每个容器的CPU百分比、内存使用量和内存上限。如果MEM USAGE / LIMIT那一列显示类似 `1.2GiB / 3.8GiB`,那个3.8GiB的LIMIT是宿主机的总内存,不是容器的限制。说明这个容器没有被限制,可以一直占用到宿主机内存耗尽。 Docker的资源限制依赖Linux cgroup(控制组),在启动容器时通过参数指定。雨云的KVM云服务器完整支持cgroup v1和v2,轻量虚拟化(如OpenVZ)可能有限制。购买前确认是KVM架构即可。 ## 内存限制:硬限制和软限制 Docker的内存限制有两个参数,作用不同: - **`--memory`(硬限制):**容器能使用的最大物理内存。超过后容器会被OOM Killer杀掉。这是最常用的限制方式 - **`--memory-reservation`(软限制):**一个建议值,当宿主机内存紧张时,Docker会尝试把容器的内存使用压到这个值以下。正常情况下容器可以超过这个值 一块配的例子: ``` # MySQL容器:硬限制512MB,软限制384MB docker run -d --name mysql --memory="512m" --memory-reservation="384m" -e MYSQL_ROOT_PASSWORD=yourpassword mysql:8.0 ``` 这个配置下:MySQL正常运行时可以用到512MB。如果VPS内存紧张,Docker会尝试把MySQL压到384MB。如果MySQL超过512MB,直接被OOM Killer杀掉。 内存单位:`m`表示MB,`g`表示GB,`k`表示KB。也可以写字节数如 `--memory="536870912"`(512MB)。 ### Docker Compose中的内存限制 在 `docker-compose.yml` 中配置: ``` services: mysql: image: mysql:8.0 deploy: resources: limits: memory: 512M reservations: memory: 384M ``` 注意 `deploy.resources` 在 `docker-compose up` 中会被忽略,只在 `docker stack deploy`(Swarm模式)中生效。如果只用 `docker-compose up`,用旧版语法: ``` services: mysql: image: mysql:8.0 mem_limit: 512m mem_reservation: 384m ``` ## CPU限制:权重、绑定和配额 CPU限制比内存复杂,有三种方式: ### 方式一:CPU权重(相对限制) ``` docker run -d --name app1 --cpu-shares=512 nginx docker run -d --name app2 --cpu-shares=1024 nginx ``` `--cpu-shares` 是一个相对权重,默认值是1024。上面两个容器:当CPU争抢时,app2分到的CPU时间是app1的两倍。但如果只有app1在跑,它可以用全部CPU——权重只在竞争时才生效。 ### 方式二:CPU配额(绝对限制) ``` # 限制容器最多使用1.5个CPU核心 docker run -d --name app --cpus="1.5" nginx ``` `--cpus` 是硬限制,容器在任何情况下都不能超过指定的CPU核心数。1.5表示最多使用一个半核心的计算能力。适合限制计算密集型容器。 ### 方式三:绑定CPU核心 ``` # 绑定到第0和第1号CPU核心 docker run -d --name app --cpuset-cpus="0,1" nginx ``` `--cpuset-cpus` 指定容器只能在哪些CPU核心上运行。适用于NUMA架构的服务器(把容器绑定到同一个NUMA节点的核心上以获得更好的内存访问性能),或者隔离噪音邻居(把批处理任务绑定到单独的核心,不干扰在线服务)。 ### Docker Compose中的CPU限制 ``` services: app: image: nginx cpus: "1.5" cpu_shares: 512 cpuset: "0,1" ``` ## 重启策略:配合资源限制使用 设置了内存限制后,容器可能因为超限被OOM杀掉。这时候需要合理的重启策略: ``` docker run -d --name app --memory="256m" --restart=on-failure:5 nginx ``` `--restart=on-failure:5` 表示容器异常退出时最多自动重启5次。如果容器因为内存超限反复被杀和重启,5次后Docker放弃重启——避免进入无限重启循环。 更安全的做法是配合健康检查: ``` docker run -d --name app --memory="256m" --restart=on-failure:3 --health-cmd="curl -f http://localhost:8080/health || exit 1" --health-interval=30s --health-retries=3 --health-timeout=5s your-app ``` 健康检查每30秒执行一次,连续3次失败才标记为unhealthy。这样内存偶尔短暂超限不会触发重启。 ## 如何确定合理的资源限制值 不是拍脑袋设一个值就完事。需要基于实际观测数据: 1. **先不设限制跑一段时间:**用 `docker stats` 持续观察容器的CPU和内存使用模式 2. **记录正常负载下的内存峰值:**比如MySQL在业务高峰期最高用到380MB 3. **留20-30%的余量设置硬限制:**380MB × 1.3 ≈ 500MB,设置 `--memory="512m"` 4. **软限制设为正常值:**`--memory-reservation="384m"` 5. **持续观察,按需调整:**如果频繁OOM,提高限制;如果长期只用一半,可以降低 对于Java应用(Spring Boot、Minecraft服务端等),注意JVM的堆内存是独立于容器内存限制的。JVM默认看到的是宿主机的总内存,需要用 `-Xmx` 参数手动限制堆大小: ``` # 容器限制512MB,JVM堆限制384MB(留128MB给堆外内存和Metaspace) docker run -d --memory="512m" -e JAVA_OPTS="-Xmx384m -Xms256m" your-java-app ``` Java 10+可以使用 `-XX:+UseContainerSupport` 让JVM自动感知容器的内存限制。 ## 监控容器资源使用 配置好限制后,持续监控确认值设得合理: ``` # 实时监控所有容器 docker stats # 查看容器的详细资源使用(包括限制值和实际使用) docker stats --no-stream --format "table {{.Name}}t{{.CPUPerc}}t{{.MemUsage}}t{{.MemPerc}}" ``` 更完整的方式是用Prometheus + Grafana或Uptime Kuma监控资源趋势。如果一台VPS上跑5个以上的容器,不看趋势很难发现哪个容器在慢慢泄漏内存。 ## OOM发生后怎么排查 如果容器被OOM Killer杀了,检查内核日志: ``` dmesg | grep -i "out of memory" dmesg | grep -i oom ``` 或者用 `docker inspect` 查看容器的退出状态: ``` docker inspect 容器名 --format='{{.State.OOMKilled}}' ``` 返回 `true` 表示这个容器是被OOM Killer杀掉的。查看容器的内存限制: ``` docker inspect 容器名 --format='{{.HostConfig.Memory}}' ``` 返回的数值单位是字节。除以1048576就是MB。 ## 一个VPS上跑多个容器的总内存规划 假设你的雨云VPS有2GB内存,跑以下服务: - 系统开销(SSH、systemd等):约200MB - MySQL:512MB限制 - Node.js应用:256MB限制 - Nginx:128MB限制 - Redis:256MB限制 - 剩余可用:约650MB 总计限制值 = 512 + 256 + 128 + 256 = 1152MB,加上系统200MB = 1352MB,在2GB的范围内有约650MB的缓冲。这个缓冲很重要——Docker本身、日志、文件缓存都需要内存。 一个常见错误:把所有容器的限制值加起来刚好等于总内存。这会导致系统缓冲空间被压缩,IO性能大幅下降。建议所有容器的限制值总和不超过总内存的70-80%。 ## 合规声明 本文所述的Docker资源限制配置属于常规的服务器运维操作。服务器的使用应遵守《网络安全法》《数据安全法》等法律法规。 **Tags:** Docker部署, Linux服务器, VPS, 雨云, 雨云优惠码 **Categories:** 网络技术 ---