Hyperf项目GitLab CI构建慢的根因是composer install和Docker层重复构建,应固定PHP镜像版本、缓存~/.composer/cache、启用BuildKit并配置--cache-from/--cache-to、换用国内高速镜像源,且四者必须协同生效。

Hyperf 项目在 GitLab CI 中构建慢,八成卡在 composer install 和 Docker 镜像层重复拉取/构建上。直接改 .gitlab-ci.yml 就能见效,不用动服务器或换 Runner。
缓存 Composer vendor 目录不等于加速
很多人以为加个 cache 把 vendor/ 缓存起来就行,但实际会出问题:
-
vendor/是二进制产物,不同 PHP 版本、扩展、平台(Linux/macOS)生成的文件不兼容,缓存混用会导致运行时报错 - GitLab 的 cache 是按 job 级别和 key 哈希分发的,多个 runner 节点之间 vendor 内容可能不一致,反而引入不确定性
- 真正该缓存的是 Composer 的全局下载缓存(
~/.composer/cache),它只存原始 zip/tar 包,安全且复用率高
正确做法是:固定 PHP 镜像版本 + 缓存 ~/.composer/cache + 使用 --prefer-dist --no-interaction --no-progress 参数
cache:
key: ${CI_COMMIT_REF_SLUG}-composer-cache
paths:
- ~/.composer/cache/并在 before_script 中确保目录存在:
before_script: - mkdir -p ~/.composer/cache
启用 BuildKit 并配置远程 Docker 层缓存
Hyperf 构建通常用多阶段 Dockerfile,但默认 Docker 构建不复用中间层。不启用 BuildKit 或没配缓存源,每次都是“冷启动”。
必须显式开启并指定缓存目标:
- 设置
DOCKER_BUILDKIT: "1"环境变量 - 用
--cache-from拉取上次成功构建的镜像层(推荐推到私有 Registry 或 GitLab Container Registry) - 用
--cache-to把本次构建的层推回去,供下次使用
示例片段:
build:
image: docker:24.0-cli
services:
- docker:24.0-dind
variables:
DOCKER_DRIVER: overlay2
DOCKER_BUILDKIT: "1"
script:
- |
docker build \
--cache-from type=registry,ref=$CI_REGISTRY_IMAGE:latest \
--cache-to type=registry,ref=$CI_REGISTRY_IMAGE:buildcache,mode=max \
--target production \
-t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA \
.
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA避免在 CI 中反复执行 composer dump-autoload
Hyperf 项目常在 CI 中跑 composer dump-autoload -o,但它依赖 vendor/ 完整性,而 vendor 又受平台差异影响。更稳的方式是:
- 把
composer dump-autoload -o放进 Dockerfile 的构建阶段(FROM php:8.2-cli阶段),不是 CI 脚本里 - 确保
composer.json和composer.lock在构建阶段就 COPY 进去,再执行 install + dump - 最终生产镜像只保留
autoload_classmap.php等优化后文件,不带composer命令本身
这样既跳过 CI 中的耗时 autoload 生成,又避免因 PHP 环境微小差异导致的 classmap 错误。
镜像源和网络策略比调优更重要
很多团队花半天调 cache key,结果发现 80% 时间耗在拉取 php:8.2-cli 或 alpine:3.20 上。国内环境尤其明显——某次实测,换用毫秒级镜像源(如 https://1ms.run)后,基础镜像拉取从 3 分钟降到 8 秒。
关键动作只有两步:
- 在 Runner 宿主机的
/etc/docker/daemon.json中配置registry-mirrors,覆盖所有常用源(Docker Hub / GHCR / quay.io) - 确保 GitLab Runner 启动时加载了新配置:
sudo systemctl restart docker && sudo gitlab-runner restart
这个改动不侵入项目代码,一次生效,所有流水线受益。比任何 CI 配置都优先做。
最易被忽略的是:BuildKit 缓存和 Composer 缓存必须配合固定基础镜像 tag(比如 php:8.2.15-cli 而非 php:8.2-cli),否则缓存 key 失效,前面所有配置都白搭。


















