缓存生效的前提是严格按顺序执行 copy composer.json composer.lock ./ 和 run composer install,中间不能插入其他指令,且 vendor 层复用依赖此顺序;否则每次构建都会重装依赖。

缓存能起效的前提,是 composer install 只依赖 composer.json 和 composer.lock 两个文件,且它们在构建流程中最早、最稳定地进入镜像层。
为什么 vendor 层总被重复安装
根本不是 Composer 慢,而是 Docker 缓存链被意外打断。只要 COPY 或 RUN 指令顺序错一丁点,上层变动就会让后续所有层失效,vendor/ 必然重装。
-
COPY . /app写在COPY composer.json composer.lock ./前面——哪怕只改了一个空格,整个依赖层就废了 - 在
COPY composer.json composer.lock ./和RUN composer install之间插了RUN chmod或RUN mkdir——Docker 认为上下文变了,缓存跳过 -
composer.lock被.dockerignore排除——构建时找不到它,composer install自动退化成update,锁文件失去意义 - 本地
vendor/被误提交进 Git,又随COPY . .覆盖掉镜像里刚装好的依赖
必须严格遵守的 COPY + RUN 顺序
这不是建议,是缓存生效的硬性条件。任何偏离都会导致每次构建都重下包、重解压、重生成 autoload。
-
COPY composer.json composer.lock ./—— 必须是第一个COPY,路径必须是./(不是/app/),否则 WORKDIR 切换后路径错位 -
RUN composer install --no-dev --optimize-autoloader --classmap-authoritative --no-scripts --no-interaction—— 紧跟其后,中间不能有任何其他RUN -
COPY . .—— 必须放在这条RUN之后,且不能用COPY . /app这类绝对路径写法(WORKDIR 已设好)
Alpine 镜像还要额外加一句:RUN apk add --no-cache ca-certificates,否则 SSL 握手失败,卡在 “Resolving packages…”
在 Linux 上通过 Docker 运行 OpenClaw,并使用 Tailscale 实现远程访问。⚠️ 涉及 sudo、Docker、Tailscale和凭证挂载——请先查阅安全章节...
BuildKit cache mount 是锦上添花,不是救命稻草
它能加速包下载,但解决不了 vendor 层复用问题。配置错一个参数,缓存就白挂。
- Dockerfile 开头必须声明:
# syntax=docker/dockerfile:1 - 启用全局 BuildKit:
export DOCKER_BUILDKIT=1,不设这个,--mount直接被忽略 - 挂载写法必须是:
RUN --mount=type=cache,target=/root/.composer/cache composer install——target路径不能错,Alpine 下用户是root,Debian 下可能是www-data,得看基础镜像 - CI 环境中若节点不共享 cache mount 存储,不同 job 的缓存互不可见,实际效果可能不如纯层缓存稳定
多阶段构建中 vendor 复制的陷阱
很多人以为 COPY --from=builder /app/vendor /app/vendor 就完事了,其实关键细节全在路径和权限里。
- builder 和 final 阶段的
WORKDIR必须完全一致,比如都是/app;如果 builder 是/app,final 是/var/www/html,autoload 就会找不到类 - 两阶段 PHP 版本和发行版必须一致:builder 用
php:8.2-cli-bullseye,final 就不能用php:8.2-fpm-alpine,扩展缺失或 platform-check 会直接报错 - 如果 builder 阶段用了
--no-scripts,而 final 阶段需要autoload_classmap.php,就得在 final 阶段补一句:RUN composer dump-autoload --classmap-authoritative - 不要在 final 阶段保留
composer二进制或composer.json——它们没用,还可能被误执行
最易被忽略的一点:所有阶段的 COMPOSER_HOME 和 COMPOSER_CACHE_DIR 环境变量最好显式统一,否则不同阶段可能往不同路径写缓存,导致 BuildKit mount 挂错地方。










