一台 Linux 服务器同时承载多个 PHP 应用时,最怕的不是负载高,而是某一个站点把 CPU、内存或进程数占满,连带拖慢其他业务。PHP-FPM 虽然本身已经提供了进程管理能力,但要做到真正可控的“互不干扰”,还需要结合 Linux 的资源和权限机制来设计。
这篇文章按实际运维中的常见路径来梳理 4 种方案:先从最容易落地的多池配置讲起,再到更底层的 cgroups、更完整的 Docker 容器化,以及适合高安全场景的 SELinux 或 AppArmor。看完后,你可以根据隔离强度、维护成本和部署方式判断哪一类方案更适合当前环境。
为什么要给 PHP-FPM 做资源隔离
PHP-FPM(FastCGI Process Manager)通常会为 Web 服务提供 PHP 进程池。如果多个应用共用一套默认配置,一旦某个应用出现慢请求、并发暴涨或内存泄漏,就可能把整台机器的可用资源一起带走。
资源隔离的核心目标,一般集中在这几类问题:
- 限制单个应用可使用的进程数、CPU 或内存,避免“抢占式”消耗;
- 将不同应用的运行身份分开,降低互相访问文件和 Socket 的风险;
- 在需要时进一步限制文件系统、系统接口或容器环境的访问范围。
从实现层次来看,PHP-FPM 池更偏向应用运行参数拆分,cgroups 偏向内核级资源限制,Docker 提供运行环境隔离,而 SELinux 或 AppArmor 则补上访问控制这一层。
方案一:用不同的 PHP-FPM 池拆分应用
这是最常见、也最容易开始的一步。PHP-FPM 支持创建多个 Pool,每个池都可以独立指定用户、组、监听地址以及进程管理参数。对多站点场景来说,它相当于给每个应用分出自己的 PHP 工作进程。

如何创建独立池配置
通常可以从主配置文件 /etc/php-fpm.d/www.conf 复制一份,改成新的池配置,例如 /etc/php-fpm.d/app1.conf:
[app1]
user = app1user
group = app1group
listen = /run/php-fpm/app1.sock
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
这组参数里,真正决定隔离效果的重点主要有三类:
user和group:让应用以独立身份运行;listen:为不同应用分配独立 Socket;pm.max_children等参数:控制该池最多能拉起多少工作进程。
修改后如何生效
配置完成后,重启 PHP-FPM 服务:
sudo systemctl restart php-fpm
这种方式的优点是简单、改动小,适合已经在裸机或虚拟机里运行多个 PHP 站点的环境。但它本质上仍然是 PHP-FPM 层面的拆分,能限制的是池配置和进程数量,无法像内核资源控制那样直接对 CPU、内存和 I/O 做硬限制。
方案二:用 cgroups 做更细粒度的资源限制
如果只是拆分 Pool 还不够,下一步通常就是上 cgroups。它是 Linux 内核提供的资源控制机制,可以对一组进程单独限制 CPU、内存、磁盘 I/O 等资源,控制粒度明显更细。
安装与创建 cgroups
先安装工具:
sudo apt-get install cgroup-tools
然后为应用创建对应的资源组:
sudo cgcreate -g memory:/app1
sudo cgcreate -g cpu:/app1
设置内存和 CPU 限额
创建完成后,就可以直接写入限制参数:
echo "100M" | sudo tee /sys/fs/cgroup/memory/app1/memory.limit_in_bytes
echo "50000" | sudo tee /sys/fs/cgroup/cpu/app1/cpu.cfs_quota_us
这里的意义很明确:
memory.limit_in_bytes用来限制该组进程的内存上限;cpu.cfs_quota_us用来约束 CPU 时间配额。
把 PHP-FPM 进程放进资源组
限制建立后,还需要把实际运行的 PHP-FPM 进程归到这个 cgroup 中。先找到 PID:
ps aux | grep php-fpm
sudo cgclassify -g memory,cpu:app1
这一步适合对资源争抢更敏感的业务环境,尤其是你已经有多池配置,但还想进一步避免某个应用把 CPU 或内存打满。相比仅使用 Pool,cgroups 的优势在于限制更硬、更接近内核;代价则是运维复杂度更高,日常管理也更依赖系统层面的经验。
方案三:用 Docker 同时隔离环境与资源
如果你的部署本身已经走向容器化,那么 Docker 往往是更完整的一种选择。它不只是限制资源,还能把运行环境、依赖和进程空间一起隔离开,每个应用都可以在独立容器里运行。
安装 Docker
sudo apt-get install docker.io
为应用准备 Dockerfile
例如为 app1 准备如下 Dockerfile:
# Dockerfile for app1
FROM php:7.4-fpm
COPY . /var/www/html
WORKDIR /var/www/html
RUN apt-get update && apt-get install -y ...
CMD ["php-fpm"]
这里保留了 php:7.4-fpm 作为基础镜像,适合直接运行 PHP-FPM 服务。
构建镜像并启动容器
构建镜像:
sudo docker build -t app1 .
运行容器:
sudo docker run -d --name app1-container -p 9000:9000 -v /path/to/app1:/var/www/html app1
Docker 的价值在于,它把“应用隔离”和“环境一致性”合并到了同一套方案里。对多项目、多版本 PHP 并存的场景尤其合适。不过这类方案通常也意味着部署链路会更长,需要额外管理镜像、容器、网络以及数据卷。
方案四:用 SELinux 或 AppArmor 增加访问控制
前面几种方法主要解决的是资源和运行环境层面的隔离,而 SELinux、AppArmor 解决的是“进程能访问什么”。对安全要求较高的场景,它们可以作为额外的一层防线,限制 PHP-FPM 对文件、目录和系统接口的访问范围。
SELinux 的基本配置
安装并启用 SELinux:
sudo apt-get install selinux-basics selinux-policy-default
sudo setenforce 1
通过审计日志生成自定义策略:
sudo ausearch -c 'php-fpm' --raw | audit2allow -M my-php-fpm
sudo semodule -i my-php-fpm.pp
这种做法适合先观察 PHP-FPM 的实际访问行为,再收敛权限边界。
AppArmor 的基本配置
安装相关工具:
sudo apt-get install apparmor apparmor-utils
新建配置文件,例如 /etc/apparmor.d/usr.sbin.php-fpm,并加入访问规则:
/usr/sbin/php-fpm {
/var/www/html/** r,
/run/php-fpm/ r,
/etc/php-fpm.d/ r,
/usr/sbin/php-fpm {
/proc/** r,
/sys/** r,
},
}
加载配置:
sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.php-fpm
和资源限制不同,SELinux 或 AppArmor 更关注访问面收缩。它们不能替代 Pool、cgroups 或 Docker,但可以与这些方案叠加使用,形成更完整的隔离体系。
怎么选:按场景组合,而不是只选一种
这四种方式并不是互斥关系,实际部署里往往会组合使用:

- 如果你只是想让多站点彼此分开,先从不同 PHP-FPM 池开始,成本最低;
- 如果机器上的资源争抢明显,进一步加上 cgroups,对 CPU 和内存做硬限制;
- 如果你已经采用容器化部署,Docker 往往更顺手,也更容易保持环境一致;
- 如果业务对权限边界要求高,再叠加 SELinux 或 AppArmor 收紧访问范围。
换句话说,没有一种方案能包打天下。更实用的判断标准是:你到底更在意部署简洁、资源硬限制、环境独立,还是安全访问控制。沿着这个顺序评估,通常比直接追求“最重”的隔离方案更有效。







