Laravel 11 生产级容器化部署:基于 tangramor/nginx-php8-fpm 镜像的完整实践指南

1. 为什么选择定制化镜像

在 Laravel 项目的容器化部署中,开发环境与生产环境的需求差异显著。官方 Sail 虽然提供了开箱即用的开发体验,但其默认配置并不适合直接用于生产环境。tangramor/nginx-php8-fpm 镜像针对生产场景做了多项优化:

  • 轻量化基础 :基于 Alpine Linux 构建,镜像体积仅 400MB(压缩后不到 200MB),相比标准开发环境节省 40% 以上空间
  • 性能优化 :预配置 OPcache、JIT 编译等 PHP 8 性能增强特性
  • 安全加固 :默认禁用危险函数、配置合理的文件权限、包含基础安全头设置
  • 多服务集成 :单镜像集成 Nginx 1.23 + PHP 8.2 FPM + Node.js 20,避免多容器通信开销
# 基础镜像选择示例
FROM php:8.2-fpm-alpine AS base
FROM node:20-alpine AS node
FROM nginx:1.23-alpine AS nginx

2. 生产级 Dockerfile 构建

2.1 基础配置

创建以下 Dockerfile 作为项目根目录的构建模板:

FROM tangramor/nginx-php8-fpm

# 设置中国区镜像源(可选)
ARG APKMIRROR="mirrors.ustc.edu.cn"
ARG COMPOSERMIRROR="https://mirrors.cloud.tencent.com/composer/"
ARG NPMMIRROR="https://registry.npmmirror.com"

# 时区与目录配置
ENV TZ="Asia/Shanghai" \
    WEBROOT="/var/www/html/public" \
    PHP_REDIS_SESSION_HOST="redis" \
    CREATE_LARAVEL_STORAGE="1"

# 复制项目文件
COPY . /var/www/html

# 构建阶段
RUN set -eux; \
    # 配置镜像源
    [ -n "$APKMIRROR" ] && sed -i "s/dl-cdn.alpinelinux.org/${APKMIRROR}/g" /etc/apk/repositories; \
    # 安装构建依赖
    apk add --no-cache --virtual .build-deps \
        gcc \
        g++ \
        libc-dev \
        make; \
    # 配置 npm 镜像
    npm config set registry ${NPMMIRROR}; \
    # 安装前端依赖
    npm install && npm run prod; \
    # 安装 PHP 依赖
    composer config -g repos.packagist composer ${COMPOSERMIRROR}; \
    composer install --no-dev --optimize-autoloader; \
    # 清理
    apk del .build-deps; \
    # 权限设置
    chown -R nginx:nginx /var/www/html

2.2 关键优化点

  1. 依赖管理

    • 使用 --no-dev 避免安装开发依赖
    • --optimize-autoloader 优化自动加载性能
  2. 构建缓存

    # 单独复制依赖描述文件以利用缓存
    COPY composer.json composer.lock package.json package-lock.json /var/www/html/
    RUN composer install --no-dev --optimize-autoloader && \
        npm install && npm run prod
    COPY . .
    
  3. 多阶段构建 (可选):

    FROM tangramor/nginx-php8-fpm AS final
    COPY --from=builder /var/www/html /var/www/html
    

3. Docker Compose 生产配置

3.1 完整服务编排

创建 docker-compose.prod.yml 文件:

version: '3.8'

services:
  app:
    build: .
    image: your-registry/laravel-app:${TAG:-latest}
    restart: unless-stopped
    env_file: .env.prod
    environment:
      - APP_ENV=production
      - APP_DEBUG=false
    volumes:
      - storage:/var/www/html/storage
      - logs:/var/log/nginx
    depends_on:
      - redis
      - db

  db:
    image: mysql:8.0
    restart: unless-stopped
    command: --default-authentication-plugin=mysql_native_password
    volumes:
      - mysql_data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
      MYSQL_DATABASE: ${DB_DATABASE}
      MYSQL_USER: ${DB_USERNAME}
      MYSQL_PASSWORD: ${DB_PASSWORD}

  redis:
    image: redis:7-alpine
    restart: unless-stopped
    volumes:
      - redis_data:/data

  scheduler:
    image: your-registry/laravel-app:${TAG:-latest}
    restart: unless-stopped
    command: |
      bash -c "while true; do
        php /var/www/html/artisan schedule:run --verbose --no-interaction;
        sleep 60;
      done"
    depends_on:
      - app
      - db
      - redis

volumes:
  mysql_data:
  redis_data:
  storage:
  logs:

3.2 关键配置说明

配置项 生产环境建议 说明
restart unless-stopped 确保服务异常退出后自动重启
APP_DEBUG false 必须关闭调试模式
数据库认证 mysql_native_password 兼容性更好的认证方式
计划任务 独立容器 避免影响 Web 服务稳定性

提示:通过 docker-compose -f docker-compose.prod.yml up -d 启动生产环境

4. 性能调优实战

4.1 PHP-FPM 配置优化

在项目根目录创建 docker/php/php-fpm.conf

[www]
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 500

; 针对 Laravel 的优化
php_admin_value[memory_limit] = 256M
php_admin_value[opcache.memory_consumption] = 128
php_admin_value[opcache.interned_strings_buffer] = 16
php_admin_value[opcache.max_accelerated_files] = 20000

4.2 Nginx 优化配置

创建 docker/nginx/nginx.conf

worker_processes auto;

events {
    worker_connections 1024;
    multi_accept on;
}

http {
    # 基础优化
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    server_tokens off;

    # Laravel 特定配置
    fastcgi_read_timeout 300;
    client_max_body_size 100m;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    # 日志格式
    log_format main '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent"';

    # Gzip 压缩
    gzip on;
    gzip_disable "msie6";
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

    include /etc/nginx/conf.d/*.conf;
}

5. 安全加固措施

5.1 镜像安全扫描

# 使用 Trivy 扫描镜像漏洞
docker build -t your-app .
trivy image your-app

# 使用 Dive 分析镜像层
dive your-app

5.2 关键安全配置

  1. 文件权限

    RUN chown -R nginx:nginx /var/www/html && \
        find /var/www/html -type f -exec chmod 644 {} \; && \
        find /var/www/html -type d -exec chmod 755 {} \; && \
        chmod -R 775 storage bootstrap/cache
    
  2. 环境变量保护

    # 生成应用密钥
    openssl rand -base64 32 | head -c 32 | base64
    
  3. CSP 头设置 (在 Nginx 配置中):

    add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' cdn.jsdelivr.net; img-src 'self' data:; font-src 'self' cdn.jsdelivr.net;";
    

6. 部署流程与 CI/CD 集成

6.1 标准部署流程

# 1. 构建镜像
docker build -t your-registry/laravel-app:$(git rev-parse --short HEAD) .

# 2. 推送镜像
docker push your-registry/laravel-app:$(git rev-parse --short HEAD)

# 3. 服务器拉取
docker pull your-registry/laravel-app:$(git rev-parse --short HEAD)

# 4. 启动服务
TAG=$(git rev-parse --short HEAD) docker-compose -f docker-compose.prod.yml up -d

# 5. 执行迁移
docker exec -it app php artisan migrate --force

6.2 GitHub Actions 示例

创建 .github/workflows/deploy.yml

name: Deploy to Production

on:
  push:
    branches: [main]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Login to Docker Hub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKER_HUB_USERNAME }}
          password: ${{ secrets.DOCKER_HUB_TOKEN }}
      
      - name: Build and push
        uses: docker/build-push-action@v4
        with:
          push: true
          tags: |
            your-registry/laravel-app:latest
            your-registry/laravel-app:${{ github.sha }}
      
      - name: Deploy to Server
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.PROD_SERVER_IP }}
          username: ${{ secrets.PROD_SERVER_USER }}
          key: ${{ secrets.PROD_SERVER_SSH_KEY }}
          script: |
            docker pull your-registry/laravel-app:${{ github.sha }}
            TAG=${{ github.sha }} docker-compose -f docker-compose.prod.yml up -d
            docker exec app php artisan migrate --force
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐