Docker 容器中 PHP 服务的内存限制需分层配置,Docker 层通过 cgroups 设定容器硬上限,PHP 层通过 `php.ini` 设定应用上限,后者数值应小于前者以预留系统开销,避免触发宿主机 OOM Killer。
先说结论:配置一致性依赖于 Docker 资源约束与 PHP 内部限制的双重管控,且需通过容器化编排固化配置。
- 适合:生产环境资源隔离、多环境配置同步场景
- 先准备:确定宿主机可用内存、编写 docker-compose.yml 与自定义 php.ini
- 验收:通过 `docker stats` 观察容器内存、通过 `phpinfo()` 确认 PHP 限制生效
命令速用版
若使用 Docker CLI 启动,直接添加内存参数;若使用 Docker Compose,需在 deploy 块中声明。
# Docker run 示例:限制容器 512MB,禁用 Swap
docker run -d `--memory`=512m `--memory-swap`=512m php:8.1-fpm
# Docker Compose 示例:resources.limits 下配置
version: '3.8'
services:
php:
image: php:8.1-fpm
deploy:
resources:
limits:
memory: 512M为什么会这样
内存限制失效通常是因为混淆了容器层限制与应用层限制。Docker 的 `--memory` 限制的是容器进程组能使用的物理内存总和,而 PHP 的 `memory_limit` 仅限制单个脚本进程。
若 PHP 限制大于 Docker 限制,PHP 脚本可能认为还有内存可用,但容器已达到 cgroups 上限,导致容器被宿主机内核强制杀死(OOM Kill)。若 PHP 限制过小,则应用频繁报错 `Allowed memory size exhausted` 但容器资源未用完。两者需配合,且 PHP 限制建议设为 Docker 限制的 70%-80% 左右,预留空间给 PHP-FPM 主进程及其他系统开销。
分步处理
1. 设定 Docker 容器硬限制
在 `docker-compose.yml` 的 `deploy.resources.limits` 下设置内存上限。注意在 Swarm 模式下该配置才完全生效,普通 compose 环境建议使用 `mem_limit` 参数(Compose V2 兼容)。
services:
php:
image: php:8.1-fpm
mem_limit: 512m
volumes:
- ./php.ini:/usr/local/etc/php/conf.d/custom.ini2. 配置 PHP 内部限制
不要直接修改容器内文件,应通过挂载卷注入配置。创建 `php.ini` 或 `conf.d` 片段,设置 `memory_limit`。
; custom.ini
memory_limit = 384M若使用 PHP-FPM,还需检查 `www.conf` 中的 `php_admin_value[memory_limit]`,该配置优先级高于 `php.ini`,会覆盖脚本中的 `ini_set` 设置。
3. 重启并固化配置
修改配置后必须重启容器,仅 reload 配置可能不生效。
docker-compose restart php怎么验证是否生效
1. 检查 Docker 层限制
使用 `docker stats` 查看实时内存使用与上限,确认 `MEM USAGE / LIMIT` 中的 LIMIT 值符合预期。
docker stats `--no-stream` php2. 检查 PHP 层限制
进入容器执行命令,确认 `memory_limit` 值已更新。
docker-compose exec php php -i | grep memory_limit输出应显示 `memory_limit => 384M => 384M`,若 Master Value 与 Local Value 不一致,说明被 `php_admin_value` 覆盖。
常见坑
1. php_admin_value 覆盖配置
在 PHP-FPM 的 `www.conf` 中,若设置了 `php_admin_value[memory_limit]`,代码中的 `ini_set('memory_limit', ...)` 将无效。需通过挂载覆盖 `www.conf` 或注释该行。
2. 忽略 PHP-FPM 多进程模型
PHP-FPM 通常运行多个子进程,`memory_limit` 是单个进程的限制。若 `pm.max_children` 设置为 10,`memory_limit` 为 384M,理论最大内存可能接近 3.8GB,需确保 Docker 容器限制能容纳峰值。
3. Swap 配置误区
单独设置 `--memory-swap` 而不设 `--memory` 无效。若希望禁用 Swap 以避免性能抖动,应将 `--memory-swap` 设为与 `--memory` 相同的值。
常见问题
为什么设置了 memory_limit 还是报 OOM?
因为 Docker 容器层面的 cgroups 限制先于 PHP 限制生效。若容器总内存超限,内核会直接杀死进程,PHP 内部限制来不及拦截。需调大 Docker 内存限制或优化代码减少占用。
本地和生产环境配置如何保持一致?
将 `docker-compose.yml` 和自定义 `php.ini` 纳入版本控制。通过环境变量区分敏感配置,但内存限制等核心参数应在配置文件中写死,避免依赖宿主机环境。
ini_set('memory_limit') 为什么不生效?
受限于 `php_admin_value` 设置。在 PHP-FPM 池配置中,管理员锁定的参数无法通过脚本动态修改,需修改容器挂载的 `www.conf` 文件。
参考来源
- 怎么在 Docker 中配置容器的资源限制保障宿主机系统的稳定
- trae 配置 php 的 memory_limit 细节_trae 内存限制注意点【步骤】
- 如何用 Docker 限制 PHP 容器资源 PHP 服务内存与 CPU 控制策略
- PHP 怎样在 Docker 容器中设置 PHP 的内存占用限制 PHP 限制内存占用的容器配置方法
- 如何用 Docker 保持 PHP 环境一致 PHP 容器化本地与生产部署