Docker多容器共享应用文件并保持可移植性的最佳实践咨询
PHP应用Docker容器集群最佳实践(自包含+自动部署)
一、解决应用文件共享与容器自包含问题
核心思路是构建一个包含完整应用代码的基础镜像,让nginx、php-fpm、worker三个服务镜像都基于这个基础镜像构建,既保持容器分离可独立扩容,又实现每个服务镜像的自包含性,无需依赖宿主主机的共享卷。
具体实现步骤
创建基础应用镜像
编写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)构建各服务镜像
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.confPHP-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 redisWorker镜像(
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
相关产品推荐
相关产品推荐

