挂载 vendor 目录会覆盖预装依赖是 docker bind mount 的必然行为,非 bug;应改用子路径挂载(如 ./src:/var/www/html/src:ro)或显式声明只读命名卷 vendor:/var/www/html/vendor:ro。

docker-compose.yml里挂载vendor目录会直接覆盖预装依赖
这不是 bug,是挂载逻辑的必然结果:Docker 的 bind mount 会把宿主机路径原样映射到容器内,如果宿主机 ./vendor 是空的或不存在,容器启动时就会看到一个空目录,覆盖掉镜像里已通过 composer install 预装好的 vendor/。
常见现象是容器能启动,但一运行就报 Class not found 或 require(): Failed opening required 'vendor/autoload.php'。
- 最简规避方式:改用子路径挂载,比如
volumes: ["./src:/var/www/html/src:ro"],避开vendor/目录 - 更稳妥做法:在
docker-compose.yml中显式声明只读空卷映射:vendor:/var/www/html/vendor:ro(需提前定义 named volume) - 若必须整目录挂载(如 legacy 项目),先在宿主机执行
mkdir -p vendor && touch vendor/.keep,确保挂载后不为空目录
开发时挂载 ~/.composer 缓存目录必须注意 UID/GID 对齐
宿主机用户和容器内用户 UID 不一致时,挂载 ${COMPOSER_HOME:-$HOME/.composer} 会导致权限拒绝,composer install 在容器内写缓存失败,最终仍走网络下载。
典型错误现象:Warning: Failed to write cache file 或反复提示包重新下载。
- 查宿主机当前 UID:
id -u,再在docker-compose.yml中用user: "1001:1001"显式指定(替换为实际 UID/GID) - 或者改用
volumes: ["${COMPOSER_CACHE_DIR:-$HOME/.composer/cache}:/root/.composer/cache"],只挂载 cache 子目录——它对 UID 敏感度更低 - Alpine 镜像要注意:
/root/.composer路径下默认无写权限,建议统一用--user www-data并确保该用户有 cache 目录写权限
macOS/Windows 下 vendor 挂载性能差不是配置问题,是文件系统限制
Docker Desktop 在 macOS 和 Windows 上使用 gRPC-FUSE 或 Hyper-V 文件共享机制,对大量小文件(如 vendor/ 里的数千个 PHP 文件)读写极慢。这不是 docker-compose.yml 参数能解决的。
表现是:容器内 composer dump-autoload 或框架启动耗时明显高于 Linux 主机。
- 开发阶段避免挂载
vendor/,改用多阶段构建 +COPY --from=builder预装依赖 - 必须挂载代码时,对 macOS 加上
:cached后缀:./src:/var/www/html/src:cached - Windows 用户可尝试启用 WSL2 后端,并把项目放在 WSL2 文件系统内(如
/home/user/project),性能提升显著
国内镜像源必须在构建阶段生效,runtime 挂载无效
很多人在 docker-compose.yml 的 volumes 里挂载本地 composer.json,以为能带入镜像源配置,但没用——因为镜像源是在 composer install 执行时读取的,而该命令发生在构建阶段(Dockerfile 的 RUN),不是容器启动时。
结果就是:构建时仍走 packagist.org,拉包巨慢;运行时即使镜像源已配置,也只影响后续动态安装(不该发生)。
- 正确做法:在
Dockerfile构建阶段加RUN composer config -g repos.packagist composer https://mirrors.aliyun.com/composer/ - 或者在项目根目录
composer.json里硬编码repositories字段,并确保该文件被COPY进构建上下文 - CI 环境中还可通过
--build-arg COMPOSER_REPO=https://mirrors.aliyun.com/composer/传参,在RUN中动态设置
docker-compose.yml,但真正起效的可能是 Dockerfile 里的 COPY 顺序,或是宿主机的 ~/.composer/cache 权限。











