排查Gradle 6.9在K8s+Jenkins Docker构建中缓存失效问题
可能忽略的关键点
1. 缓存目录的权限与挂载问题
Kubernetes挂载的/var深层路径,大概率存在权限不匹配的情况。本地构建时,Gradle运行用户对缓存目录有读写权限,但Jenkins的K8s Pod里,执行Docker构建的用户可能和缓存目录所有者不一致,导致Gradle读不了也写不了缓存。可以在构建脚本里加一行ls -la ~/.gradle/caches或者实际缓存路径的查看命令,确认运行Gradle的用户有对应权限。
2. Docker镜像缓存层被打破
你用构建后保存镜像当基础镜像的思路没问题,但如果Dockerfile里的指令顺序不对——比如先复制代码再做Gradle构建,会导致Docker缓存层失效,后续基于该镜像构建时,Gradle缓存目录根本没被复用。要把依赖安装、Gradle缓存相关的步骤放在Dockerfile前面,动态代码复制放在后面。另外还要检查.dockerignore,别把Gradle的caches和wrapper目录排除了,确保这些缓存目录完整保存在镜像里。
3. Gradle缓存配置被覆盖
Gradle 6.9默认开启本地缓存,但服务器环境可能有配置被覆盖:
- 查
gradle.properties里有没有org.gradle.caching=false的配置,或者Jenkins构建时有没有通过参数关掉缓存; - 确认
--build-cache参数确实传对了,没被Jenkins脚本或Docker命令漏掉; - 因为访问不了scan.gradle.org,要确保
settings.gradle里没配置远程缓存(比如HttpBuildCache),虽然Gradle默认不会因为远程缓存失效禁用本地缓存,但万一配置了远程缓存且无法连接,可能影响缓存逻辑,直接把远程缓存设为enabled=false更稳妥。
4. Kubernetes存储卷的特性问题
如果Gradle缓存目录挂载在K8s的PersistentVolume(PV)上,可能是卷的读写模式不对——比如设成了ReadOnlyMany导致写不了缓存;或者分布式存储的元数据不一致,Gradle识别不出已有的缓存文件。可以先在Pod里手动创建文件测试挂载路径的读写权限,或者临时换成emptyDir卷试试,排除存储卷的问题。
如何查看Gradle缓存决策的原因
Gradle有详细日志能追踪缓存命中情况,用这两种方式:
启用详细日志
在构建命令里加--info或--debug参数,比如:gradle --build-cache --no-daemon classes bootJar --info日志里搜
cache关键词,比如Task ... is not cacheable、Task ... uses cache entry、Cache key is ...,这些信息会直接告诉你Gradle为什么不用缓存——比如输入文件变了、任务属性改了、缓存目录访问不了等等。生成缓存报告
Gradle 6.9支持生成缓存报告,构建完成后看build/reports/build-cache下的HTML报告,里面会列每个任务的缓存状态、命中/未命中原因。如果没生成,在settings.gradle里加这段配置启用:buildCache { local { enabled = true removeUnusedEntriesAfterDays = 30 } remote(HttpBuildCache) { enabled = false } }
临时优化:先搞定Maven依赖缓存
如果全构建缓存暂时搞不定,先单独缓存Maven依赖也能省大量时间:
- Dockerfile里先复制
build.gradle和settings.gradle,执行gradle dependencies或gradle wrapper --gradle-version 6.9(用wrapper的话),这样Docker会缓存依赖下载的层,只要依赖文件不变,就不会重新下载; - 把Gradle的
wrapper目录和caches/modules-2目录挂载成K8s持久卷,让依赖缓存跨构建复用,不用每次都保存镜像。
内容的提问来源于stack exchange,提问作者Thorbjørn Ravn Andersen

