gitlab runner 的 composer 缓存需显式设置 composer_cache_dir,否则仍写入默认 ~/.composer/cache;cache: 块仅声明文件路径,不自动影响 composer 运行时行为,必须配合环境变量、目录创建授权及基于 composer.lock 的 cache key 才能生效。

GitLab Runner 的 Composer 缓存必须显式设 COMPOSER_CACHE_DIR,否则它根本不会写进你声明的 cache: 路径里——默认仍往 ~/.composer/cache 写,而那个目录在 CI 环境中通常权限不对或根本不存在。
为什么 cache: 块不生效?
GitLab CI 的 cache: 是文件系统级缓存机制,和 Composer 运行时完全解耦。Composer 不会自动感知 cache: 声明的路径,它只认环境变量 COMPOSER_CACHE_DIR 或全局配置里的 cache-dir。如果你只写了:
cache: - .composer-cache/
但没告诉 Composer “请把缓存写到这儿”,它就会继续用默认路径(比如 /home/gitlab-runner/.composer/cache),而该路径往往归属 root 或压根没初始化,导致 Permission denied 或静默 fallback 到临时目录。
必须在 before_script 中设置环境变量
Runner 以 gitlab-runner 用户运行,所以所有路径必须针对该用户,且需提前创建并授权:
- 在
before_script中执行:mkdir -p "$CI_PROJECT_DIR/.composer-cache" && chmod 700 "$CI_PROJECT_DIR/.composer-cache" - 紧接着 export:
export COMPOSER_CACHE_DIR="$CI_PROJECT_DIR/.composer-cache" - 或者更稳妥地,在
variables:块中直接定义:COMPOSER_CACHE_DIR: "$CI_PROJECT_DIR/.composer-cache" - 确保该变量透传到后续所有命令——某些 Runner 配置会清空环境,加
export -g或用script:包裹整段逻辑更可靠
缓存 key 必须包含 composer.lock 校验值
即使路径对了,如果 key 没变,GitLab 可能复用旧缓存,而旧缓存是用不同 PHP 版本、不同镜像源或不同 lock 文件生成的,Composer 会拒绝使用(校验失败),表现为命中率始终为 0:
- key 推荐写成:
composer-$CI_COMMIT_REF_SLUG-$([ -f composer.lock ] && sha256sum composer.lock | cut -d' ' -f1 || echo "no-lock") - 避免只用
$CI_COMMIT_REF_SLUG或$CI_RUNNER_TAG——它们不反映依赖实际内容 - 如果项目未提交
composer.lock,缓存将失效;务必保证 lock 文件存在且已提交
验证是否真生效的三步法
别信配置“看起来对”,得看 Composer 自己的日志:
- 执行
composer config --global cache-dir:输出应为空(因为你不该改全局配置,而应靠环境变量驱动) - 执行
php -r "echo getenv('COMPOSER_CACHE_DIR');":必须输出你设的完整路径,如/builds/group/project/.composer-cache - 跑一次
composer install -vvv,搜索日志里的Writing into cache行:路径必须和上面一致,且能看到files/子目录下生成了哈希命名的 zip 包
最常被忽略的是:环境变量设置了,但没 export 到子 shell;或是 cache: 路径和 COMPOSER_CACHE_DIR 值不一致,导致 GitLab 同步了 A 目录,而 Composer 写的是 B 目录——两者彻底错开。











