必须用--cpus和-m硬性限制mysql容器资源,因--cpu-shares仅为相对权重、无内存上限则必触发oom killer。

直接限制 MySQL 容器的 CPU 和内存,必须用 --cpus 和 -m(或 --memory),否则它会吃光宿主机资源,尤其在导入大库、执行复杂查询或连接数突增时极易触发 OOM Kill。
为什么不能只靠 --cpu-shares 或不设内存上限
MySQL 是典型的“内存敏感型 + CPU 持续占用型”服务:它会主动缓存数据页(innodb_buffer_pool_size)、预分配连接内存、并可能因慢查询长期占满单核。仅设 --cpu-shares=512 没用——它只在多个容器抢 CPU 时起作用;宿主机空闲时,MySQL 仍可跑满所有核。同样,不设 -m 就等于放任它把宿主机内存耗尽,mysqld 进程会被内核直接杀掉,日志里只留一句 Killed process 1234 (mysqld),连错误码都不给。
-
--cpu-shares是相对权重,不是硬限制;MySQL 容器没竞争对手时,它就默认拿走全部 CPU -
-m是硬边界,超限即被 OOM Killer 终止;而--memory-reservation只是软提示,对 MySQL 几乎无效 - MySQL 启动时若发现可用内存远大于
innodb_buffer_pool_size,会按需分配,直到触达 cgroup 上限
docker run 中设置 MySQL 资源配额的关键参数组合
生产环境推荐用以下组合启动 MySQL 容器,兼顾稳定性与可预测性:
-
--cpus=1.0:硬性限制最多使用 1 个完整 CPU 核心(等价于每 100ms 周期最多用 100ms),避免单个慢查询拖垮整个节点 -
-m 1g:强制内存上限为 1GB;同时必须配--memory-swap=1g,禁用 swap,防止 IO 拖累响应 -
--restart=unless-stopped:OOM 后自动重启,但要配合监控告警,不能依赖它兜底 - 额外建议加
--pids-limit=200:防 fork 炸弹类攻击(MySQL 连接数暴增时可能派生大量线程)
完整命令示例:
docker run -d \ --name mysql-limited \ --cpus=1.0 \ -m 1g \ --memory-swap=1g \ --pids-limit=200 \ -e MYSQL_ROOT_PASSWORD=root123 \ -v ./mysql-data:/var/lib/mysql \ -p 3306:3306 \ mysql:8.0
docker-compose.yml 中的等效配置写法
用 Compose 部署更易维护,但注意字段嵌套层级和单位格式:
-
cpus字段值必须是字符串(如'1.0'),不是数字,否则 Docker 会忽略 -
memory单位大小写敏感:1G可以,1g也可以,但1GB会报错 -
deploy.resources.limits是 Swarm 模式专用;单机 Compose 请用mem_limit和cpus顶层字段
正确写法(单机 Compose v3+):
version: '3.8'
services:
mysql:
image: mysql:8.0
cpus: '1.0'
mem_limit: 1G
mem_reservation: 512M
pids_limit: 200
environment:
MYSQL_ROOT_PASSWORD: root123
volumes:
- ./mysql-data:/var/lib/mysql
ports:
- "3306:3306"
验证限制是否生效及常见失效点
启动后立刻验证,别等出问题才查:
- 运行
docker stats mysql-limited:看CPU %是否稳定在 100% 以下(比如 98.3% 表示已卡在 1 核上限),MEM USAGE / LIMIT是否显示987MiB / 1GiB - 进容器执行
cat /sys/fs/cgroup/memory/memory.limit_in_bytes,应返回1073741824(即 1GB) - 如果
docker stats显示内存持续接近上限但没被 kill,检查 MySQL 的innodb_buffer_pool_size是否设得过大(例如设了 800M 但容器只有 1G,留给 OS 和其他进程的空间就极小) - 如果 CPU 使用率始终低于 100% 却响应慢,可能是磁盘 I/O 瓶颈,这时得加
--device-read-bps=/dev/sda:5mb类限制,而非调高 CPU
最常被忽略的一点:MySQL 容器内看到的 /proc/meminfo 仍是宿主机总内存,它不会自动适配 cgroup 限制——所以你必须手动在 my.cnf 里把 innodb_buffer_pool_size 设为略小于 -m 值(比如 -m 1g 时设 innodb_buffer_pool_size = 768M),否则 MySQL 启动就可能失败或运行中被 OOM。











