GitLab CI DIND环境Gradle依赖缓存不生效问题咨询
问题根因
日志显示缓存提取成功,仅代表Runner完成了缓存包解压动作,不代表Gradle可以正常识别、使用缓存内容。当前配置有4个核心遗漏,导致缓存不命中:
- 缓存key默认按分支隔离,跨分支无法复用
未显式配置cache:key时,GitLab CI生成的默认缓存key会绑定当前分支标识,从日志的default-8-non_protected也能看出该特性:不同分支(develop、octopus、独立MR分支)会使用完全独立的缓存空间,只有同一分支的第二次构建才能命中对应缓存,MR场景下新建分支首次构建必然全量下载依赖。如果你的私有Runner是多实例负载且未配置共享存储,任务调度到不同Runner时也会因为本地缓存不互通触发重复下载。 - 缓存路径配置不全,缺少Gradle必要的元数据目录
当前仅缓存了.gradle/wrapper和.gradle/caches两个路径,缺失两类关键内容:- 项目根目录下的
.gradle目录(非GRADLE_USER_HOME下的路径):存放当前项目的依赖解析索引、任务缓存元数据,缺失后Gradle会重新扫描、校验所有依赖包,产生大量下载类日志; - Gradle wrapper下载的分发包目录、构建缓存目录:
.gradle/wrapper/dists存的是Gradle二进制包,.gradle/caches/build-cache-1存的是构建输出缓存,缺失会触发wrapper、依赖的重新下载。
- 项目根目录下的
- 目录权限冲突导致Gradle无法读取缓存
配置了GIT_STRATEGY: clone时,每次构建会先清空工作目录拉取代码,再恢复缓存。openjdk:8-jdk镜像如果以非root用户运行(部分定制镜像会默认创建普通运行用户),恢复出来的.gradle目录权限为root所有,Gradle进程无读写权限时会直接判定缓存损坏,跳过缓存重新下载依赖到临时路径。 - Gradle运行参数未适配CI场景,缓存策略过于保守
未添加任何缓存相关启动参数时,Gradle默认对SNAPSHOT版本依赖的缓存有效期仅24小时,且默认不开启构建缓存复用,哪怕本地已有依赖包,也会发起远程校验请求,产生大量下载日志,同时不会复用历史构建输出。
另外你把GRADLE_USER_HOME的定义写在before_script中通过export注入,存在作用域失效风险:如果后续其他job重写了before_script没继承该配置,就会直接使用镜像内默认的/root/.gradle路径,和你缓存的工作目录下的.gradle完全不匹配。
可直接复用的修复配置
全局配置调整
把全局的变量、缓存配置改成如下内容,把GRADLE_USER_HOME提前声明为全局变量,补全缓存路径、优化缓存key规则:
image: docker:stable services: - name: docker:dind variables: BUILD_IMAGE: "openjdk:8-jdk" # 全局声明Gradle用户目录,避免export作用域问题,$CI_PROJECT_DIR就是GitLab CI默认的项目工作目录 GRADLE_USER_HOME: "$CI_PROJECT_DIR/.gradle" cache: key: # 按依赖配置文件生成缓存key,只有gradle wrapper、构建脚本变更时才会生成新缓存 files: - gradle/wrapper/gradle-wrapper.properties - build.gradle - settings.gradle prefix: gradle-global-cache paths: - .gradle/caches - .gradle/wrapper - .gradle/build-cache # 默认所有任务仅拉取缓存,避免重复上传浪费时间 policy: pull
build-job配置调整
补全权限修复、Gradle缓存参数,配置该任务负责推送更新后的缓存:
build-job: image: $BUILD_IMAGE stage: build variables: GIT_STRATEGY: clone GIT_SUBMODULE_STRATEGY: normal cache: # 继承全局缓存配置,当前任务完成后推送更新的缓存 policy: pull-push script: # 修复缓存目录权限,确保运行用户有读写权限 - chmod -R 777 .gradle || true # 开启构建缓存,优先使用本地依赖,仅本地缺失时才发起远程下载 - ./gradlew clean classes jasperCompilerTask --build-cache --offline -Dorg.gradle.daemon=false -Dorg.gradle.caching=true -x test - ./gradlew properties -q | grep "version:" | awk '{print $2}' >> project_version only: refs: - develop - octopus - merge_requests variables: - $BRANCH_TO_MERGE == null artifacts: paths: - project_version - deployment-scripts/deploy.sh
额外注意事项
- 首次应用配置时先去掉
--offline参数跑一次,确保全量依赖下载完成并上传缓存,后续构建再加回--offline参数即可。 - 如果是多台Runner做负载均衡,必须配置MinIO/S3等共享缓存存储,否则缓存存在Runner本地磁盘,任务调度到其他节点时依然无法命中。
- 不要在script中随意切换工作目录,确保执行
./gradlew命令时的工作目录为项目根目录,和缓存路径匹配。
内容的提问来源于stack exchange,提问作者PabPabPab
相关产品推荐
相关产品推荐

