# Docker 部署 PHP 项目最佳实践:从开发到生产
> **标签:** `docker` `php` `deployment` `devops` `nginx`
> **作者:** @docker_fan
> **发布时间:** 2026-06-12
## 为什么使用 Docker?
在团队开发中,经常遇到"在我电脑上能运行"的问题。Docker 通过容器化技术,确保开发、测试、生产环境的一致性。
## 项目结构
```
my-php-project/
├── docker/
│ ├── nginx/
│ │ └── default.conf
│ ├── php/
│ │ ├── Dockerfile
│ │ └── php.ini
│ ├── mysql/
│ │ └── my.cnf
│ └── redis/
│ └── redis.conf
├── docker-compose.yml
├── docker-compose.prod.yml
├── .dockerignore
└── src/
└── ...
```
## 第一步:PHP Dockerfile
```dockerfile
# docker/php/Dockerfile
FROM php:8.2-fpm
# 安装依赖
RUN apt-get update && apt-get install -y \
libpng-dev \
libjpeg-dev \
libfreetype6-dev \
libzip-dev \
libonig-dev \
libxml2-dev \
zip \
unzip \
git \
curl \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install -j$(nproc) \
pdo_mysql \
mysqli \
gd \
zip \
bcmath \
opcache \
intl
# 安装 Redis 扩展
RUN pecl install redis && docker-php-ext-enable redis
# 安装 Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# 配置 PHP
COPY docker/php/php.ini /usr/local/etc/php/php.ini
# 工作目录
WORKDIR /var/www/html
# 权限设置
RUN chown -R www-data:www-data /var/www/html
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD php-fpm -t || exit 1
EXPOSE 9000
CMD ["php-fpm"]
```
## 第二步:Nginx 配置
```nginx
# docker/nginx/default.conf
server {
listen 80;
server_name localhost;
root /var/www/html/public;
index index.php index.html;
# 日志
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
# PHP 处理
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
# 性能优化
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
}
# 静态文件
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# 禁止访问敏感文件
location ~ /\. {
deny all;
}
}
```
## 第三步:Docker Compose 配置
### 开发环境
```yaml
# docker-compose.yml
version: '3.8'
services:
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./src:/var/www/html
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
- ./logs/nginx:/var/log/nginx
depends_on:
- php
networks:
- app-network
php:
build:
context: .
dockerfile: docker/php/Dockerfile
volumes:
- ./src:/var/www/html
environment:
- APP_ENV=development
- DB_HOST=mysql
- DB_PORT=3306
- REDIS_HOST=redis
depends_on:
- mysql
- redis
networks:
- app-network
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: myapp
MYSQL_USER: appuser
MYSQL_PASSWORD: apppass
volumes:
- mysql_data:/var/lib/mysql
- ./docker/mysql/my.cnf:/etc/mysql/conf.d/my.cnf
ports:
- "3306:3306"
networks:
- app-network
redis:
image: redis:alpine
volumes:
- redis_data:/data
- ./docker/redis/redis.conf:/usr/local/etc/redis/redis.conf
command: redis-server /usr/local/etc/redis/redis.conf
networks:
- app-network
# 可选:phpMyAdmin
phpmyadmin:
image: phpmyadmin/phpmyadmin
ports:
- "8080:80"
environment:
PMA_HOST: mysql
PMA_PORT: 3306
depends_on:
- mysql
networks:
- app-network
volumes:
mysql_data:
redis_data:
networks:
app-network:
driver: bridge
```
### 生产环境
```yaml
# docker-compose.prod.yml
version: '3.8'
services:
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./src:/var/www/html:ro
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
- ./ssl:/etc/nginx/ssl:ro
- ./logs/nginx:/var/log/nginx
depends_on:
- php
networks:
- app-network
restart: unless-stopped
php:
build:
context: .
dockerfile: docker/php/Dockerfile
volumes:
- ./src:/var/www/html:ro
environment:
- APP_ENV=production
- DB_HOST=mysql
- REDIS_HOST=redis
depends_on:
- mysql
- redis
networks:
- app-network
restart: unless-stopped
deploy:
resources:
limits:
cpus: '1'
memory: 512M
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
MYSQL_DATABASE: myapp
MYSQL_USER: appuser
MYSQL_PASSWORD_FILE: /run/secrets/db_password
volumes:
- mysql_data:/var/lib/mysql
- ./docker/mysql/my.cnf:/etc/mysql/conf.d/my.cnf:ro
secrets:
- db_root_password
- db_password
networks:
- app-network
restart: unless-stopped
redis:
image: redis:alpine
volumes:
- redis_data:/data
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
networks:
- app-network
restart: unless-stopped
secrets:
db_root_password:
file: ./secrets/db_root_password.txt
db_password:
file: ./secrets/db_password.txt
volumes:
mysql_data:
redis_data:
networks:
app-network:
driver: bridge
```
## 第四步:常用命令
```bash
# 构建并启动
docker-compose up -d --build
# 查看日志
docker-compose logs -f php
# 进入 PHP 容器
docker-compose exec php bash
# 执行 Composer 安装
docker-compose exec php composer install
# 运行数据库迁移
docker-compose exec php php artisan migrate
# 重启服务
docker-compose restart nginx
# 停止并删除
docker-compose down -v
# 生产环境部署
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
```
## 第五步:CI/CD 集成
### GitHub Actions 示例
```yaml
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build Docker Image
run: |
docker build -t myapp:${{ github.sha }} -f docker/php/Dockerfile .
docker tag myapp:${{ github.sha }} myapp:latest
- name: Push to Registry
run: |
echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
docker push myapp:${{ github.sha }}
- name: Deploy to Server
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.SSH_KEY }}
script: |
cd /var/www/myapp
docker-compose pull
docker-compose up -d
docker system prune -f
```
## 性能优化
### 1. OPcache 配置
```ini
; docker/php/php.ini
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.revalidate_freq=2
opcache.fast_shutdown=1
```
### 2. Nginx 优化
```nginx
# 在 http 块中
worker_processes auto;
worker_connections 4096;
# Gzip 压缩
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml;
```
## 安全建议
1. **使用非 root 用户**运行容器
2. **定期更新**基础镜像
3. ** secrets 管理**敏感信息
4. **网络隔离**使用自定义网络
5. **资源限制**设置 CPU/内存限制
6. **健康检查**配置容器健康检查
## 常见问题
### 1. 权限问题
```bash
# 修复文件权限
docker-compose exec php chown -R www-data:www-data /var/www/html/storage
```
### 2. 时区问题
```dockerfile
# Dockerfile 中
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo "Asia/Shanghai" > /etc/timezone
```
### 3. 内存不足
```yaml
# docker-compose.yml
services:
php:
deploy:
resources:
limits:
memory: 1G
```
## 总结
Docker 化部署的优势:
- ✅ 环境一致性,避免"在我电脑上能运行"
- ✅ 快速部署,分钟级搭建环境
- ✅ 资源隔离,多个项目互不干扰
- ✅ 易于扩展,支持水平扩展
---
**讨论:** 你在 Docker 部署中遇到过哪些问题?欢迎分享解决方案!
- 本文链接:
- https://bbs.lgdfort.com/?post=108
- 版权声明:本论坛所有文章除特别声明外,均默认采用 CC BY-NC-SA 4.0 许可协议。
支持便是对本站最大的助力!
还没有人为TA充电
为TA充电
-
支付宝扫一扫 -
微信扫一扫
感谢支持
支持便是对本站最大的助力!

![[知识大区] Docker 部署 PHP 项目最佳实践:从开发到生产](https://bbs.lgdfort.com/content/uploadfile/202606/3f9f1781405243.webp)


![[知识大区] VS Code 效率开发完全指南:从入门到精通封面](https://bbs.lgdfort.com/content/uploadfile/202606/89801781195951.webp)


