构建PHP Docker基础镜像时vendor目录缺失,容器主机同步失败
问题:PHP镜像构建阶段生成的vendor目录消失的排查与解决
场景描述
尝试搭建PHP基础镜像作为应用基座,计划在镜像构建阶段完成项目初始化及依赖包安装,但执行docker-compose up --build后,主机和容器中均未生成vendor目录,导致应用无法运行。
相关配置文件
Dockerfile
ARG PHP_VERSION=8.1.9 FROM php:${PHP_VERSION}-cli-alpine # ARG PECL_OPENSWOOLE_VERSION=4.11.1 RUN apk update \ && apk add --no-cache \ supervisor \ tree \ vim \ --update linux-headers \ && rm -rf /tmp/pear # supervisord setup RUN mkdir -p /etc/supervisor/ \ && mkdir -p /var/log/supervisord/ COPY docker/dev/php-cli/config/supervisord.conf /etc/supervisor/conf.d/supervisord.conf # install composer COPY --from=composer:latest /usr/bin/composer /usr/bin/composer COPY . /srv/www/ WORKDIR /srv/www RUN mkdir -p vendor RUN chown -R www-data: /srv/www USER www-data RUN composer validate --strict RUN composer install USER root ENTRYPOINT ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
项目目录结构
├── Makefile ├── bin │ └── console ├── composer.json ├── config ├── docker │ └── dev │ ├── nginx │ │ └── app.conf │ └── php-cli │ ├── Dockerfile │ └── config │ └── supervisord.conf ├── docker-compose.yaml └── src └── user.php
docker-compose.yaml
version: '3.9' services: app: build: context: . dockerfile: docker/dev/php-cli/Dockerfile volumes: - .:/srv/www/
问题根源
核心原因是绑定挂载覆盖了镜像内的目录:
当docker-compose up启动容器时,./:/srv/www的挂载规则会将主机当前目录的内容完全覆盖容器内的/srv/www目录。由于主机目录原本没有vendor文件夹,构建阶段在镜像内生成的vendor就被覆盖掉了,导致容器内和主机都看不到该目录。
解决方案
方案1:保留镜像内的vendor目录,避免挂载覆盖
修改docker-compose.yaml,添加一条挂载规则,让容器内的/srv/www/vendor目录不被主机挂载覆盖:
version: '3.9' services: app: build: context: . dockerfile: docker/dev/php-cli/Dockerfile volumes: - .:/srv/www/ - /srv/www/vendor # 这条规则会保留镜像内的vendor目录,不受主机挂载影响
方案2:优化Dockerfile构建逻辑,提升缓存效率
原Dockerfile先复制整个项目再执行composer install,每次代码变更都会触发重新安装依赖。调整后先复制composer相关文件,利用Docker构建缓存,仅当composer.json或composer.lock变更时才重新安装依赖:
ARG PHP_VERSION=8.1.9 FROM php:${PHP_VERSION}-cli-alpine # ARG PECL_OPENSWOOLE_VERSION=4.11.1 RUN apk update \ && apk add --no-cache \ supervisor \ tree \ vim \ linux-headers \ && rm -rf /tmp/pear # supervisord setup RUN mkdir -p /etc/supervisor/ \ && mkdir -p /var/log/supervisord/ COPY docker/dev/php-cli/config/supervisord.conf /etc/supervisor/conf.d/supervisord.conf # install composer COPY --from=composer:latest /usr/bin/composer /usr/bin/composer # 先复制composer配置文件,利用构建缓存 WORKDIR /srv/www COPY composer.json composer.lock* ./ RUN mkdir -p vendor \ && chown -R www-data: /srv/www USER www-data RUN composer validate --strict \ && composer install # 可根据需求添加--no-dev、--optimize-autoloader等参数 # 最后复制项目代码 USER root COPY . /srv/www/ RUN chown -R www-data: /srv/www USER www-data ENTRYPOINT ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
额外验证步骤
- 单独运行镜像(不挂载目录),检查vendor是否存在:
docker run --rm $(docker build -q . -f docker/dev/php-cli/Dockerfile) ls /srv/www/vendor - 如果需要主机也同步vendor目录,可从容器拷贝:
docker cp $(docker ps -qf "name=app"):/srv/www/vendor ./
内容的提问来源于stack exchange,提问作者mina.nsami
相关产品推荐
相关产品推荐

