本文目录导读:

我来详细介绍PHP项目的容器化部署方法,包括基础实践和进阶优化。
基础Docker部署
1 最简Dockerfile
# 使用官方PHP镜像 FROM php:8.2-apache # 安装扩展 RUN docker-php-ext-install pdo_mysql mysqli # 复制项目文件 COPY . /var/www/html/ # 设置工作目录 WORKDIR /var/www/html # 配置Apache RUN a2enmod rewrite EXPOSE 80
2 生产环境优化版
# 多阶段构建
FROM composer:2 AS composer
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --no-scripts --prefer-dist
# 运行时镜像
FROM php:8.2-fpm-alpine
# 安装系统依赖
RUN apk add --no-cache \
nginx \
curl \
icu-dev \
libzip-dev \
oniguruma-dev \
libxml2-dev \
freetype-dev \
libjpeg-turbo-dev \
libpng-dev
# 安装PHP扩展
RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install \
pdo_mysql \
mysqli \
gd \
zip \
intl \
mbstring \
exif \
pcntl \
bcmath \
opcache
# 复制项目代码
COPY --from=composer /app/vendor /app/vendor
COPY . /app
# 配置目录权限
RUN chown -R www-data:www-data /app \
&& chmod -R 755 /app/storage /app/bootstrap
WORKDIR /app
EXPOSE 9000
CMD ["php-fpm"]
Docker Compose配置
version: '3.8'
services:
# PHP应用
app:
build:
context: .
dockerfile: Dockerfile
container_name: php_app
restart: unless-stopped
working_dir: /var/www/html
volumes:
- ./src:/var/www/html
- ./docker/php/php.ini:/usr/local/etc/php/conf.d/php.ini:ro
networks:
- app-network
depends_on:
- db
- redis
# Nginx服务
nginx:
image: nginx:alpine
container_name: nginx_server
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./src:/var/www/html
- ./docker/nginx/conf.d:/etc/nginx/conf.d:ro
- ./docker/nginx/ssl:/etc/nginx/ssl:ro
networks:
- app-network
depends_on:
- app
# MySQL数据库
db:
image: mysql:8.0
container_name: mysql_db
restart: unless-stopped
environment:
MYSQL_DATABASE: ${DB_DATABASE}
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
MYSQL_USER: ${DB_USERNAME}
MYSQL_PASSWORD: ${DB_PASSWORD}
volumes:
- db_data:/var/lib/mysql
- ./docker/mysql/init:/docker-entrypoint-initdb.d
ports:
- "3306:3306"
networks:
- app-network
# Redis缓存
redis:
image: redis:7-alpine
container_name: redis_cache
restart: unless-stopped
ports:
- "6379:6379"
volumes:
- redis_data:/data
networks:
- app-network
networks:
app-network:
driver: bridge
volumes:
db_data:
redis_data:
Nginx配置
1 Nginx配置文件 (docker/nginx/conf.d/default.conf)
server {
listen 80;
server_name localhost;
root /var/www/html/public;
index index.php index.html;
# 请求头配置
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
# 日志配置
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
# 静态文件缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
# PHP请求处理
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass app:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTP_PROXY "";
fastcgi_read_timeout 120s;
}
# 拒绝访问隐藏文件
location ~ /\.(?!well-known) {
deny all;
}
}
PHP配置优化
1 php.ini配置 (docker/php/php.ini)
; 内存限制 memory_limit = 256M max_execution_time = 120 max_input_time = 60 post_max_size = 50M upload_max_filesize = 50M ; 错误报告 display_errors = Off log_errors = On error_log = /var/log/php/error.log error_reporting = E_ALL ; 时区设置 date.timezone = Asia/Shanghai ; 会话配置 session.save_handler = files session.gc_maxlifetime = 1440 session.cookie_httponly = 1 session.use_strict_mode = 1 ; OpCache优化 opcache.enable = 1 opcache.memory_consumption = 128 opcache.interned_strings_buffer = 8 opcache.max_accelerated_files = 4000 opcache.revalidate_freq = 60 opcache.fast_shutdown = 1
进阶优化
1 健康检查
# docker-compose.yml 中添加
app:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/ping"]
interval: 30s
timeout: 3s
retries: 3
start_period: 40s
db:
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 30s
timeout: 5s
retries: 5
2 日志轮转
# 使用logrotate
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
3 自动部署脚本
#!/bin/bash
# deploy.sh
set -e
# 环境变量
ENV=${1:-production}
COMPOSE_FILE="docker-compose.${ENV}.yml"
echo "部署环境: ${ENV}"
# 构建新镜像
docker compose -f ${COMPOSE_FILE} build --no-cache
# 停止旧容器
docker compose -f ${COMPOSE_FILE} down
# 启动新容器
docker compose -f ${COMPOSE_FILE} up -d
# 清理旧镜像
docker image prune -f
# 等待服务启动
sleep 10
# 执行数据库迁移
docker compose -f ${COMPOSE_FILE} exec app php artisan migrate --force
# 缓存清理
docker compose -f ${COMPOSE_FILE} exec app php artisan config:cache
docker compose -f ${COMPOSE_FILE} exec app php artisan route:cache
# 检查状态
docker compose -f ${COMPOSE_FILE} ps
echo "部署完成!"
CI/CD集成
1 GitHub Actions示例
name: CI/CD Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: 设置环境
uses: actions/setup-php@v2
with:
php-version: '8.2'
extensions: mbstring, intl, pdo_mysql
- name: 安装依赖
run: composer install --no-dev --prefer-dist --no-interaction
- name: 构建Docker镜像
run: |
docker build -t ${{ secrets.DOCKER_REGISTRY }}/php-app:${{ github.sha }} .
docker tag ${{ secrets.DOCKER_REGISTRY }}/php-app:${{ github.sha }} ${{ secrets.DOCKER_REGISTRY }}/php-app:latest
- name: 推送镜像
run: |
docker push ${{ secrets.DOCKER_REGISTRY }}/php-app:${{ github.sha }}
docker push ${{ secrets.DOCKER_REGISTRY }}/php-app:latest
- name: 部署到服务器
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USERNAME }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /var/www/php-app
docker-compose pull
docker-compose up -d
安全最佳实践
1 Dockerfile安全建议
# 使用非root用户 RUN useradd -m -u 1000 app # 限制资源使用 RUN ulimit -n 65536 # 最小化攻击面 RUN apt-get clean && rm -rf /var/lib/apt/lists/* # 设置只读文件系统 VOLUME ["/app/storage", "/app/bootstrap/cache"]
2 网络隔离
# 使用不同的网络分段
networks:
frontend:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16
backend:
driver: bridge
internal: true
监控和日志
# 集成Prometheus
prometheus:
image: prom/prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
这个完整方案涵盖了PHP项目容器化的所有核心要素,建议从小型项目开始实践,逐步增加功能,记住定期更新镜像和依赖,保持系统安全。