根本原因是 macOS/Windows 文件系统与 Linux 容器间 I/O 延迟高、stat/inotify 开销大,而 Composer 频繁操作 vendor 中大量小文件;应避免挂载 vendor 目录,改用容器内安装、多阶段构建或缓存挂载选项。

在 Docker for Mac/Windows 中,把 vendor 目录直接挂载进容器(比如用 -v $(pwd)/vendor:/app/vendor)会导致 Composer 安装、更新极慢,甚至卡死。根本原因是 macOS 和 Windows 的文件系统通过 gRPC-FUSE(Mac)或 Hyper-V 文件共享(Win)与 Linux 容器交互,I/O 延迟高、stat/inotify 开销大,而 Composer 在 vendor 目录中频繁读写成千上万个小文件。
避免挂载 vendor 目录本身
这是最直接有效的解法:不要把 vendor 挂进容器,让依赖完全在容器内管理。
- 本地
composer.json和composer.lock可以挂载(只读更安全),用于构建时安装 - 运行时的
vendor留在容器内部的分层文件系统里,享受原生 Linux I/O 性能 - 开发时如需调试 vendor 代码,用 IDE 远程调试或容器内终端,而非靠挂载同步
用多阶段构建 + COPY 替代运行时挂载
适合 CI/CD 或本地开发镜像构建流程:
- 第一阶段:基于
php:alpine或php:slim,COPYcomposer.json和composer.lock,运行composer install --no-dev --no-scripts --optimize-autoloader - 第二阶段:轻量运行镜像(如
php:alpine-apache),只 COPY 第一阶段的/app/vendor和你的源码 - 这样最终镜像不含 Composer,vendor 是静态、优化过的,启动快、无挂载开销
启用 Docker 的 “cached” 或 “delegated” 挂载选项(仅限开发环境)
如果确实需要在开发中动态修改 vendor(不推荐,但有时调试必需),可在 docker run 或 docker-compose.yml 中显式指定挂载一致性:
- Mac:用
:cached(推荐)或:delegated,例如-v $(pwd)/vendor:/app/vendor:cached - Windows:用
:cached(Docker Desktop 4.16+ 支持),旧版可尝试:delegated - 注意:
:cached会缓存目录元数据,减少 stat 调用;:delegated允许宿主异步写入,降低容器侧阻塞 - ⚠️ 不要对整个
vendor启用:consistent(默认值),那是最慢的
用 bind mount 替代 volume + 清理无用缓存
Docker Desktop 的 volume 驱动在 Mac/Win 上有额外抽象层,而 bind mount 更接近原生路径映射:
- 优先用
-v $(pwd)/vendor:/app/vendor:cached(bind mount),而不是-v my-vendor-volume:/app/vendor(named volume) - 定期清理 Docker Desktop 缓存:Docker Desktop → Troubleshoot → Clean / Purge data(尤其 vendor 变更频繁后)
- 关闭不必要的文件监控工具(如 Dropbox、OneDrive 同步
vendor目录),它们会加剧 inotify 压力
基本上就这些。核心原则是:vendor 不该是“共享区”,而是“构建产物”。挂载它就像给固态硬盘套上软盘驱动器——技术上可行,但违背设计本意。不复杂,但容易忽略。











