You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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两个路径,缺失两类关键内容:
    1. 项目根目录下的.gradle目录(非GRADLE_USER_HOME下的路径):存放当前项目的依赖解析索引、任务缓存元数据,缺失后Gradle会重新扫描、校验所有依赖包,产生大量下载类日志;
    2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 12:27:17