一、为什么要把PHP应用装进容器?
老式的LAMP架构就像住在集体宿舍——Apache、MySQL和PHP挤在同一台服务器上,谁打个喷嚏整个系统都可能感冒。想象这样一个场景:你的电商网站在促销时突然流量暴增,传统架构下只能整机扩容,而实际上可能只是PHP服务需要更多资源。
容器化就像给每个服务分配独立公寓。我们去年将公司CRM系统从CentOS物理机迁移到Docker后,部署时间从2小时缩短到5分钟。更重要的是,当PHP需要版本切换时,再也不用担心影响其他服务。
二、Docker化改造实战步骤
1. 准备标准化的PHP环境
(技术栈:PHP 7.4 + Docker)
# 使用官方PHP镜像作为基础
FROM php:7.4-fpm
# 安装常用扩展(注释说明每个扩展用途)
RUN docker-php-ext-install \
pdo_mysql \ # 数据库连接
opcache \ # 性能优化
bcmath \ # 精确计算
&& pecl install redis-5.3.4 \ # Redis缓存
&& docker-php-ext-enable redis
# 配置PHP生产环境参数
COPY ./php.ini /usr/local/etc/php/conf.d/custom.ini
# 设置工作目录
WORKDIR /var/www/html
这个Dockerfile做了三件关键事:选择合适的基础镜像、安装必要扩展、应用优化配置。特别注意我们使用fpm版本而非apache版本,这样能更灵活搭配Nginx。
2. 处理文件挂载难题
传统LAMP应用通常把代码放在/var/www/html,但容器化时需要特别注意:
# 启动容器时挂载代码和配置文件
docker run -d \
-v /path/to/your/code:/var/www/html \ # 代码目录
-v /path/to/php-fpm.conf:/usr/local/etc/php-fpm.d/www.conf \ # PHP进程配置
-p 9000:9000 \ # 暴露PHP-FPM端口
--name php-app \
your-php-image
建议在开发环境使用bind mount直接挂载代码目录,生产环境则应该构建包含代码的镜像保证一致性。
三、那些年我们踩过的坑
1. 会话(Session)处理问题
原先使用文件存储session的方式在容器集群中会出问题。这是我们改造后的方案:
// 在应用初始化处配置Redis存储session
ini_set('session.save_handler', 'redis');
ini_set('session.save_path', 'tcp://redis:6379?auth=yourpassword');
// 普通session操作不受影响
session_start();
$_SESSION['user'] = 'docker_admin';
2. 静态文件服务策略
PHP容器不应该直接服务静态文件,正确的做法是:
server {
location ~ \.php$ {
fastcgi_pass php:9000; # 连接到PHP容器
include fastcgi_params;
}
location ~* \.(jpg|css|js)$ {
expires 30d; # 静态文件缓存
root /var/www/html;
}
}
这种架构下,Nginx容器处理静态请求,动态请求转发给PHP容器,效率比Apache的mod_php高出40%左右。
四、进阶优化技巧
1. 多阶段构建减小镜像体积
# 构建阶段
FROM php:7.4-cli as builder
COPY . /app
RUN cd /app && \
curl -sS https://getcomposer.org/installer | php -- \
&& ./composer.phar install --no-dev
# 生产阶段
FROM php:7.4-fpm-alpine
COPY --from=builder /app /var/www/html
这个技巧让我们的生产镜像从780MB缩小到210MB,拉取时间缩短65%。
2. 健康检查配置
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost:8080/health-check.php || exit 1
配合Kubernetes的探针,可以实现自动故障转移。去年双11期间,这个机制帮我们自动恢复了3次突发故障。
五、迁移决策指南
适合容器化的场景:
- 需要频繁部署更新的系统
- 多环境一致性要求高的项目
- 准备上云或混合云部署的应用
- 需要弹性伸缩的业务系统
不建议立即改造的情况:
- 重度依赖特定服务器硬件的遗留系统
- 使用非标准PHP模块的自定义环境
- 短期内计划重构的整体架构
六、完整示例:电商应用改造
(技术栈:PHP + MySQL + Redis)
version: '3.8'
services:
php:
build: ./php
volumes:
- ./src:/var/www/html
environment:
- DB_HOST=mysql
- REDIS_HOST=redis
mysql:
image: mysql:5.7
volumes:
- mysql_data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=secret
redis:
image: redis:6-alpine
nginx:
image: nginx:1.21
ports:
- "8080:80"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
- ./src:/var/www/html
volumes:
mysql_data:
这个配置实现了:
- PHP与数据库分离
- 开发/生产环境一致
- 独立扩展各服务
- 数据持久化存储
七、性能对比实测数据
我们将相同的WordPress站点部署在两种环境测试:
| 指标 | 传统LAMP | Docker化 |
|---|---|---|
| 部署时间 | 47分钟 | 6分钟 |
| 100并发响应 | 820ms | 560ms |
| 故障恢复 | 人工干预 | 自动恢复 |
| 资源利用率 | 62% | 78% |
八、安全注意事项
- 永远不要使用
latest标签 - 定期扫描镜像漏洞:
docker scan your-php-image
- 容器内使用非root用户运行:
RUN groupadd -r phpuser && useradd -r -g phpuser phpuser
USER phpuser
- 敏感信息通过环境变量注入:
docker run -e DB_PASSWORD=secret ...
九、未来演进方向
当容器数量超过20个时,建议考虑:
- 使用Kubernetes管理集群
- 实现CI/CD自动化流水线
- 采用Service Mesh管理服务通信
- 引入APM工具监控性能
我们团队在完成Docker化半年后,逐步实施了这套进阶方案,现在每天可以完成50+次安全部署。
评论