只要 composer.json 和 composer.lock 不变且最早单独 COPY,Docker 就能跳过 composer install;否则因 COPY 顺序错误(如 COPY . . 在前)或锁文件缺失/未提交,会导致 vendor 层缓存必然失效。

只要 composer.json 和 composer.lock 不变,Docker 就能跳过 composer install 这一层——但前提是它们必须最早被复制,且不能混在其他文件里一起 COPY。
为什么 vendor 层总不命中缓存?
最常见原因是 COPY 顺序错了:把整个项目目录 COPY . . 放在 composer install 前面,导致每次代码改一行,Docker 都得重跑依赖安装。缓存失效不是因为 Composer 本身问题,而是构建指令破坏了层依赖链。
- 必须先单独
COPY composer.json composer.lock ./,中间不能插任何其他COPY或RUN -
composer.lock缺失或未提交到 Git,会导致每次解析版本,缓存必然失效 - 本地开发时若把
vendor/提交进 Git,COPY . .会直接覆盖掉前面装好的vendor/,白忙一场
哪些 composer install 参数真正影响缓存稳定性?
参数不是越多越好,关键要排除运行时不确定因素。比如 --no-interaction 防止卡在交互提示,--no-dev 避免开发依赖引入环境差异——这两项直接影响缓存是否跨机器复用。
-
--no-dev:跳过 dev 依赖,否则不同机器上可能装出不同包(如 phpunit 版本浮动) -
--no-interaction:确保构建不因缺失输入而中断,也避免因 prompt 差异触发缓存重建 -
--optimize-autoloader:不影响缓存逻辑,但能减少后续 RUN 指令的副作用(比如生成 autoload_files.php) - 别用
--ignore-platform-reqs:它绕过 PHP 扩展检查,可能导致镜像在目标环境跑不起来,缓存再稳也没用
BuildKit 的 cache mount 到底要不要开?
它能加速包下载,但解决不了 vendor 层复用这个核心问题。而且一旦 CI 节点不共享 cache mount 存储,就容易出现“本地构建快、CI 构建慢”或“PHP 版本兼容报错”这类难排查的问题。
- 启用方式:
RUN --mount=type=cache,id=composer-cache,dest=/root/.composer/cache composer install ... - 实际收益有限:90%+ 场景下,靠分层 COPY + 锁文件稳定已足够;加了 cache mount 反而让构建行为更难预测
- CI 环境慎用:如果多个 job 并发构建,cache mount 可能冲突,导致
Package foo has a PHP requirement incompatible with your PHP version这类错误 - 替代方案更可靠:在 CI 中挂载宿主机的
~/.composer/cache到构建容器,比 BuildKit cache mount 更可控
缓存命中的关键不在工具多先进,而在 COPY 的时机是否足够早、锁文件是否足够稳、参数是否足够克制——稍一松动,整个依赖层就重新下载、解压、安装,所有优化都归零。


















