如何用PHP项目实现容器化部署?

wen java案例 1

本文目录导读:

如何用PHP项目实现容器化部署?

  1. 核心准备:准备 Dockerfile
  2. 开发环境的容器化(Docker Compose)
  3. 生产环境的容器化部署
  4. 部署流程
  5. 常见问题与最佳实践
  6. 超越 Docker:Kubernetes

使用PHP项目实现容器化部署,核心是通过 Docker 将你的PHP应用(代码、运行环境、依赖、配置)打包成一个独立的、可移植的镜像,然后运行在容器中。

以下是完整的步骤指南,分为 开发环境生产环境 两个常见场景。


核心准备:准备 Dockerfile

这是容器化的蓝图,根据你的项目类型(纯PHP脚本、Laravel/Symfony框架、或传统LAMP/LEMP),Dockerfile 略有不同。

基础Dockerfile(使用PHP官方镜像 + FPM + Composer)

对于大多数现代PHP框架,推荐使用 php:8.x-fpm 作为基础镜像,并配合 Nginx 容器。

Dockerfile

# 1. 使用官方PHP 8.2 FPM 镜像作为基础
FROM php:8.2-fpm-alpine AS base
# 2. 安装系统依赖和 PHP 扩展 (根据你的项目需求)
RUN apk add --no-cache \
    git \
    unzip \
    libpng-dev \
    libjpeg-turbo-dev \
    freetype-dev \
    oniguruma-dev \
    libxml2-dev \
    zip \
    curl \
    && docker-php-ext-configure gd --with-freetype --with-jpeg \
    && docker-php-ext-install \
        pdo_mysql \
        mbstring \
        exif \
        pcntl \
        bcmath \
        gd \
        opcache
# 3. 安装 Composer (PHP包管理器)
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# 4. 设置工作目录
WORKDIR /var/www/html
# 5. 复制项目文件 (先复制 composer.json 等依赖文件,利用Docker缓存)
COPY composer.json composer.lock ./
# 6. 安装项目依赖 (生产环境不安装 dev 依赖)
RUN composer install --no-interaction --prefer-dist --optimize-autoloader --no-dev
# 7. 复制项目源代码 (这时才复制源码,如果前面没变化会走缓存)
COPY . .
# 8. 设置文件权限 (重要: 确保 PHP-FPM 用户 `www-data` 可以写 storage, cache 等)
RUN chown -R www-data:www-data /var/www/html/storage /var/www/html/bootstrap/cache \
    && chmod -R 775 /var/www/html/storage /var/www/html/bootstrap/cache
# 9. 暴露 PHP-FPM 的端口 (9000)
EXPOSE 9000
# 10. 启动命令
CMD ["php-fpm"]

开发环境的容器化(Docker Compose)

在本地开发时,你通常需要 PHP + Web 服务器 + 数据库 + Redis 等服务。docker-compose.yml 可以一键搞定。

docker-compose.yml (放在项目根目录):

version: '3.8'
services:
  # PHP 服务 (使用上面的 Dockerfile)
  app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: php-app
    volumes:
      - .:/var/www/html  # 挂载本地代码,方便热更新
    networks:
      - app-network
  # Web 服务器 (Nginx)
  nginx:
    image: nginx:alpine
    container_name: php-nginx
    ports:
      - "8080:80"  # 本机 8080 端口映射到容器 80 端口
    volumes:
      - .:/var/www/html
      - ./nginx.conf:/etc/nginx/conf.d/default.conf  # 自定义 Nginx 配置
    depends_on:
      - app
    networks:
      - app-network
  # 数据库 (MySQL)
  database:
    image: mysql:8.0
    container_name: php-mysql
    environment:
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_DATABASE: my_database
      MYSQL_USER: user
      MYSQL_PASSWORD: password
    ports:
      - "3307:3306"
    volumes:
      - db_data:/var/lib/mysql
    networks:
      - app-network
  # 缓存 (Redis) - 可选
  redis:
    image: redis:alpine
    container_name: php-redis
    networks:
      - app-network
networks:
  app-network:
    driver: bridge
volumes:
  db_data:

关键点

  • .env 文件中 DB_HOSTREDIS_HOST 应填写服务名称:databaseredis
  • docker-compose up -d 即可启动所有服务。
  • 访问 http://localhost:8080 查看项目。

生产环境的容器化部署

生产环境更注重安全性、多阶段构建、环境变量和健康检查。

多阶段构建 (减小镜像体积)

只保留运行所需的文件,去掉构建时用的工具(如Composer、Git)。

# --- 第一阶段:构建阶段 ---
FROM php:8.2-fpm-alpine AS builder
RUN apk add --no-cache git unzip
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
WORKDIR /var/www/html
COPY composer.json composer.lock ./
RUN composer install --no-interaction --prefer-dist --no-dev
COPY . .
RUN php artisan optimize  # 生产环境优化:路由、配置、视图缓存
# --- 第二阶段:运行阶段 (最终镜像) ---
FROM php:8.2-fpm-alpine
# 只复制最终需要的东西
COPY --from=builder /var/www/html /var/www/html
WORKDIR /var/www/html
USER www-data
EXPOSE 9000
CMD ["php-fpm"]

Docker Compose 生产配置 (docker-compose.prod.yml)

version: '3.8'
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile.prod   # 使用多阶段构建的 Dockerfile
    image: my-project/app:latest
    environment:
      - APP_ENV=production
      - APP_DEBUG=false
      - DB_HOST=database
      - DB_DATABASE=my_db
      - DB_USERNAME=user
      - DB_PASSWORD=${DB_PASSWORD}   # 使用 .env 文件或外部环境变量
    # 不挂载卷,而是将镜像推送到仓库
    # volumes:
    #   - .:/var/www/html   <-- 生产环境中不要挂载代码!
    networks:
      - app-network
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
      - ./ssl:/etc/ssl   # 证书挂载
    depends_on:
      - app
    networks:
      - app-network
  database:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: my_db
      MYSQL_USER: user
      MYSQL_PASSWORD: ${DB_PASSWORD}
    volumes:
      - db_prod_data:/var/lib/mysql
    networks:
      - app-network
networks:
  app-network:
    driver: bridge
volumes:
  db_prod_data:

Nginx 配置示例 (nginx.conf)

server {
    listen 80;
    server_name localhost;  # 生产环境改为你的域名
    root /var/www/html/public;  # Laravel 入口
    index index.php index.html;
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
    location ~ \.php$ {
        fastcgi_pass app:9000;  # 指向 PHP-FPM 服务
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
    location ~ /\.ht {
        deny all;
    }
}

部署流程

  1. 环境变量管理:使用 .env 文件(docker-compose 会自动读取),或使用 Docker Swarm / Kubernetes 的 Secrets。
  2. 构建镜像
    docker build -t my-project/app:latest -f Dockerfile.prod .
  3. 推送镜像到仓库(如 Docker Hub、AWS ECR、阿里云镜像仓库):
    docker tag my-project/app:latest your-registry.com/my-project/app:1.0.0
    docker push your-registry.com/my-project/app:1.0.0
  4. 在服务器上部署
    # 拉取最新镜像
    docker pull your-registry.com/my-project/app:1.0.0
    # 使用 docker-compose 启动(生产配置)
    docker-compose -f docker-compose.prod.yml up -d
  5. CI/CD 整合:在 GitHub Actions / GitLab CI 中自动执行 docker builddocker push

常见问题与最佳实践

问题 解决方案
文件权限 确保容器内的 www-data 用户对 storagebootstrap/cache 有读写权限,使用 chownsetfacl
数据库连接 使用服务名称作为主机名(如 database),而不是 localhost0.0.1
配置缓存 生产环境需运行 php artisan config:cachephp artisan route:cache 以提高性能。
日志 将日志输出到 stdoutstderr,以便 Docker 自动收集(php-fpm 默认支持)。
健康检查 在 Dockerfile 中添加 HEALTHCHECK 指令,或使用 docker-composehealthcheck
进程管理 一个容器只运行一个进程(PHP-FPM),Web 服务器用单独的 Nginx 容器。
镜像大小 使用 Alpine 基础镜像(约100MB)替代 Debian(约300MB+)。

超越 Docker:Kubernetes

当你的项目需要多实例、自动扩缩容、滚动更新时,可以转向 Kubernetes:

# 简单的 Deployment 示例
apiVersion: apps/v1
kind: Deployment
metadata:
  name: php-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: php-app
  template:
    metadata:
      labels:
        app: php-app
    spec:
      containers:
      - name: php-app
        image: my-project/app:1.0.0
        ports:
        - containerPort: 9000
        env:
        - name: APP_ENV
          value: production
        - name: DB_HOST
          value: mysql-service

  • Dockerfile:定义 PHP 运行环境,安装扩展和依赖。
  • docker-compose.yml:在本地将 PHP + Nginx + DB 等编排在一起,方便开发。
  • 多阶段构建:生产环境中减小镜像体积。
  • 不挂载代码:生产环境通过镜像部署代码,而不是挂载卷。
  • 环境变量:通过 .env 或 Kubernetes Secrets 管理敏感信息。

按照这个流程,你可以将一个 PHP 项目高效且可靠地在任何支持 Docker 的环境中运行。

抱歉,评论功能暂时关闭!