问题背景与适用场景

在当前软件开发环境中,容器化技术已成为部署应用的标准方式之一。Docker 作为容器化技术的代表,为 PHP 应用提供了轻量级、可移植、可扩展的部署方案。无论是传统的 PHP 应用,还是基于现代框架(如 Laravel、Symfony)的应用,都可以通过 Docker 实现环境一致性,解决"在我机器上能运行"的问题。Docker 部署 PHP 应用特别适用于以下场景:

  • 需要确保开发、测试和生产环境一致的情况
  • 需要快速扩展 PHP 应用以应对流量高峰
  • 多个应用共享同一台服务器,需要资源隔离
  • 持续集成/持续部署(CI/CD)流程集成
  • 微服务架构中的 PHP 服务部署

原理部分

Docker 使用容器来打包应用及其依赖,实现环境隔离。在 PHP 应用的 Docker 部署中,核心原理包括:

  1. 镜像(Image):包含应用代码、运行时环境、系统工具、依赖库等的只读模板。PHP 应用通常基于官方 PHP 镜像进行定制。
  1. 容器(Container):镜像的运行实例,拥有独立的文件系统、进程空间和网络栈。每个容器都是隔离的,互不影响。
  1. Dockerfile:定义如何构建应用镜像的文本文件,包含一系列命令和指令。
  1. Docker Compose:用于定义和运行多容器 Docker 应用工具,通过 YAML 文件配置应用的服务、网络和数据卷。
  1. 网络:容器间通信的机制,支持桥接、主机、覆盖等多种网络模式。
  1. 数据卷(Volume):用于持久化容器数据的存储机制,即使容器被删除,数据仍然保留。

操作步骤

1. 准备工作

  • 安装 Docker 和 Docker Compose
  • 准备 PHP 应用代码

2. 创建 Dockerfile

在项目根目录创建 Dockerfile,定义如何构建应用镜像:

# 选择基础镜像
FROM php:8.1-fpm

# 设置工作目录
WORKDIR /var/www/html

# 安装系统依赖和 PHP 扩展
RUN apt-get update && apt-get install -y \
    git \
    curl \
    libpng-dev \
    libonig-dev \
    libxml2-dev \
    zip \
    unzip \
    && docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd

# 安装 Composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

# 复制应用代码
COPY . .

# 设置权限
RUN chown -R www-data:www-data /var/www/html
RUN usermod -u 1000 www-data

# 暴露端口
EXPOSE 9000

# 启动 PHP-FPM
CMD ["php-fpm"]

3. 创建 docker-compose.yml

在项目根目录创建 docker-compose.yml,定义服务、网络和数据卷:

version: '3.8'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: php-app
    volumes:
      - ./:/var/www/html
    networks:
      - app-network

  webserver:
    image: nginx:alpine
    container_name: nginx-server
    ports:
      - "8080:80"
    volumes:
      - ./:/var/www/html
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - app
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

4. 创建 Nginx 配置

创建 docker/nginx/default.conf 文件:

server {
    listen 80;
    index index.php index.html;
    root /var/www/html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass app:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

5. 构建和运行容器

在项目根目录执行以下命令:

# 构建并启动服务
docker-compose up -d

# 查看运行状态
docker-compose ps

# 查看日志
docker-compose logs -f

6. 访问应用

打开浏览器,访问 http://localhost:8080,即可查看 PHP 应用。

示例代码

下面是一个简单的 Laravel 应用的 Docker 部署示例:

Laravel 项目的 Dockerfile

FROM php:8.1-fpm

# 安装系统依赖
RUN apt-get update && apt-get install -y \
    git \
    curl \
    libpng-dev \
    libonig-dev \
    libxml2-dev \
    zip \
    unzip \
    && rm -rf /var/lib/apt/lists/*

# 安装 PHP 扩展
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd

# 安装 Composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

# 设置工作目录
WORKDIR /var/www

# 复制依赖文件
COPY composer.json composer.lock ./

# 安装依赖
RUN composer install --no-dev --no-interaction --no-scripts --optimize-autoloader

# 复制应用代码
COPY . .

# 设置权限
RUN chown -R www-data:www-data /var/www/storage /var/www/bootstrap/cache
RUN chmod -R 775 /var/www/storage /var/www/bootstrap/cache

# 暴露端口
EXPOSE 9000

# 启动 PHP-FPM
CMD ["php-fpm"]

Laravel 项目的 docker-compose.yml

version: '3.8'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: laravel-app
    volumes:
      - ./:/var/www
    environment:
      - DB_HOST=mysql
      - DB_PORT=3306
      - DB_DATABASE=laravel
      - DB_USERNAME=root
      - DB_PASSWORD=root
    depends_on:
      - mysql
    networks:
      - app-network

  webserver:
    image: nginx:alpine
    container_name: nginx-server
    ports:
      - "8080:80"
    volumes:
      - ./:/var/www
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - app
    networks:
      - app-network

  mysql:
    image: mysql:5.7
    container_name: mysql-db
    environment:
      MYSQL_DATABASE: laravel
      MYSQL_ROOT_PASSWORD: root
    volumes:
      - mysql-data:/var/lib/mysql
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

volumes:
  mysql-data:
    driver: local

常见问题与注意事项

  1. 权限问题:
  • 在容器内运行的应用可能没有足够的权限写入文件系统
主楼