You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker多容器共享应用文件并保持可移植性的最佳实践咨询

PHP应用Docker容器集群最佳实践(自包含+自动部署)

一、解决应用文件共享与容器自包含问题

核心思路是构建一个包含完整应用代码的基础镜像,让nginx、php-fpm、worker三个服务镜像都基于这个基础镜像构建,既保持容器分离可独立扩容,又实现每个服务镜像的自包含性,无需依赖宿主主机的共享卷。

具体实现步骤

  1. 创建基础应用镜像
    编写Dockerfile.base,将应用代码复制到镜像内,同时安装通用依赖:

    # 基于PHP 8.2-fpm的Alpine镜像,兼顾轻量性和功能
    FROM php:8.2-fpm-alpine
    
    WORKDIR /var/www/html
    
    # 复制本地应用代码到镜像
    COPY . .
    
    # 安装Composer并加载应用依赖
    RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
        && composer install --no-dev --optimize-autoloader
    

    构建并推送到Docker Hub(用Git短提交哈希作为版本标签,保证可追溯):

    docker build -t your-dockerhub-username/my-app-base:$(git rev-parse --short HEAD) -f Dockerfile.base .
    docker push your-dockerhub-username/my-app-base:$(git rev-parse --short HEAD)
    
  2. 构建各服务镜像

    • Nginx镜像(Dockerfile.nginx):

      FROM nginx:alpine
      
      # 从基础镜像复制应用代码到Nginx的静态文件目录
      COPY --from=your-dockerhub-username/my-app-base:$(git rev-parse --short HEAD) /var/www/html /var/www/html
      
      # 复制自定义Nginx配置(指向静态文件和PHP-FPM地址)
      COPY ./nginx/default.conf /etc/nginx/conf.d/default.conf
      
    • PHP-FPM镜像(Dockerfile.php-fpm):

      FROM your-dockerhub-username/my-app-base:$(git rev-parse --short HEAD)
      
      # 安装PHP-FPM专属扩展(如Redis、PDO)
      RUN docker-php-ext-install pdo_mysql \
          && pecl install redis \
          && docker-php-ext-enable redis
      
    • Worker镜像(Dockerfile.worker):

      FROM your-dockerhub-username/my-app-base:$(git rev-parse --short HEAD)
      
      # 设置Worker启动命令(以Laravel队列worker为例)
      CMD ["php", "artisan", "queue:work", "--sleep=3", "--tries=3"]
      

    每个服务镜像都自带完整应用代码,部署时无需宿主准备共享卷,直接拉取镜像即可运行。

二、构建自动部署流水线

用Github Actions触发镜像构建推送,配合Watchtower自动更新生产容器,实现代码推送后全自动化部署。

1. Github Actions配置(自动构建推送镜像)

在项目根目录创建.github/workflows/deploy.yml:

name: Build and Push Docker Images

on:
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Generate short commit hash
        id: vars
        run: echo "COMMIT_HASH=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT

      - name: Build and push base image
        uses: docker/build-push-action@v5
        with:
          context: .
          file: Dockerfile.base
          push: true
          tags: your-dockerhub-username/my-app-base:${{ steps.vars.outputs.COMMIT_HASH }}

      - name: Build and push nginx image
        uses: docker/build-push-action@v5
        with:
          context: .
          file: Dockerfile.nginx
          push: true
          tags: your-dockerhub-username/my-app-nginx:${{ steps.vars.outputs.COMMIT_HASH }}

      - name: Build and push php-fpm image
        uses: docker/build-push-action@v5
        with:
          context: .
          file: Dockerfile.php-fpm
          push: true
          tags: your-dockerhub-username/my-app-php-fpm:${{ steps.vars.outputs.COMMIT_HASH }}

      - name: Build and push worker image
        uses: docker/build-push-action@v5
        with:
          context: .
          file: Dockerfile.worker
          push: true
          tags: your-dockerhub-username/my-app-worker:${{ steps.vars.outputs.COMMIT_HASH }}

注意:在Github仓库的Settings > Secrets and variables > Actions中添加DOCKERHUB_USERNAME和DOCKERHUB_TOKEN(Docker Hub的访问令牌)。

2. 生产环境配置(Watchtower自动更新)

编写生产环境的docker-compose.prod.yml:

version: '3.8'

services:
  nginx:
    image: your-dockerhub-username/my-app-nginx:${COMMIT_HASH}
    ports:
      - "80:80"
    depends_on:
      - php-fpm

  php-fpm:
    image: your-dockerhub-username/my-app-php-fpm:${COMMIT_HASH}
    depends_on:
      - redis

  worker:
    image: your-dockerhub-username/my-app-worker:${COMMIT_HASH}
    depends_on:
      - redis
      - php-fpm
    deploy:
      replicas: 2  # 按需扩容worker数量

  redis:
    image: redis:alpine

  watchtower:
    image: containrrr/watchtower
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ~/.docker/config.json:/config.json  # 用于Docker Hub私有镜像认证
    command: --interval 30 --cleanup --notification-email your-email@example.com
    environment:
      - WATCHTOWER_NOTIFICATION_EMAIL_FROM=watchtower@example.com
      - WATCHTOWER_NOTIFICATION_EMAIL_TO=your-email@example.com
      - WATCHTOWER_NOTIFICATION_EMAIL_SERVER=smtp.example.com
      - WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PORT=587
      - WATCHTOWER_NOTIFICATION_EMAIL_SERVER_USER=smtp-user
      - WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PASSWORD=smtp-password

部署时设置最新镜像标签并启动:

export COMMIT_HASH=$(git rev-parse --short HEAD)
docker-compose -f docker-compose.prod.yml up -d

Watchtower会每隔30秒检查镜像更新,发现新标签后自动拉取并重启对应容器,同时清理旧镜像、发送更新通知。

三、关键注意事项

  • 镜像标签管理:始终用Git提交哈希或语义化版本作为标签,避免latest标签导致的版本混乱。
  • 环境变量分离:应用配置(如Redis地址、数据库连接)通过environment或.env文件传递,不要硬编码到镜像中。
  • 镜像分层优化:基础镜像仅包含代码和通用依赖,服务镜像只添加专属配置和扩展,减少镜像体积。
  • 私有镜像认证:若使用私有仓库,确保生产环境的config.json包含Docker Hub认证信息,让Watchtower正常拉取镜像。

内容的提问来源于stack exchange,提问作者Drallinx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 23:30:26