Docker构建中Gradle缓存丢失求助:如何保留RUN生成的缓存?
问题
我有一个自定义镜像,里面包含测试所需的所有Gradle依赖缓存。但最近发现新构建的镜像中缓存消失了,推测是公司CI管理员升级了Docker导致的。
我的Dockerfile内容如下:
FROM gradle:7.6-jdk11 COPY . . RUN gradle test && ls -l .gradle/caches RUN ls -l .gradle/caches
gradle test会在.gradle/caches目录生成缓存,但执行下一条RUN指令时,缓存却消失了。
构建日志如下:
... Step 3/4 : RUN gradle test && ls -l .gradle/caches ---> Running in b19404b6a13f ... Starting a Gradle Daemon ... BUILD SUCCESSFUL total 8 drwxr-xr-x 7 gradle gradle 98 Aug 28 08:24 . drwxr-xrwx 12 gradle gradle 160 Aug 28 08:26 .. drwxr-xr-x 12 gradle gradle 4096 Aug 28 08:26 7.6.4 drwxr-xr-x 6 gradle gradle 185 Aug 28 08:24 jars-9 drwxr-xr-x 2 gradle gradle 81 Aug 28 08:24 journal-1 drwxr-xr-x 4 gradle gradle 67 Aug 28 08:24 modules-2 -rw-r--r-- 1 gradle gradle 4 Aug 28 08:23 tmp drwxr-xr-x 2 gradle gradle 6 Aug 28 08:24 transforms-3 Removing intermediate container b19404b6a13f ---> 01b0d3b3a1a7 Step 4/4 : RUN ls -l .gradle/caches ---> Running in e0b1e4fe1b59 total 4 drwxr-xr-x 2 gradle gradle 17 Aug 28 08:26 . drwxr-xrwx 5 gradle gradle 55 Aug 28 08:26 .. -rw-r--r-- 1 gradle gradle 4 Aug 28 08:23 tmp Removing intermediate container e0b1e4fe1b59 ---> 659e47228e5d Successfully built 659e47228e5d
最终镜像中没有.gradle/caches目录,请问如何防止Docker删除我的缓存?
Docker版本及信息:
docker version Client: Docker Engine - Community Version: 24.0.6 API version: 1.43 Go version: go1.20.7 Git commit: ed223bc Built: Mon Sep 4 12:32:10 2023 OS/Arch: linux/amd64 Context: default Server: Docker Engine - Community Engine: Version: 24.0.6 API version: 1.43 (minimum version 1.12) Go version: go1.20.7 Git commit: 1a79695 Built: Mon Sep 4 12:32:10 2023 OS/Arch: linux/amd64 Experimental: true containerd: Version: 1.6.24 GitCommit: 61f9fd88f79f081d64d6fa3bb1a0dc71ec870523 runc: Version: 1.1.9 GitCommit: v1.1.9-0-gccaecfc docker-init: Version: 0.19.0 GitCommit: de40ad0 [Pipeline] sh docker info Client: Docker Engine - Community Version: 24.0.6 Context: default Debug Mode: false Server: Containers: 29 Running: 20 Paused: 0 Stopped: 9 Images: 48 Server Version: 24.0.6 Storage Driver: overlay2 Backing Filesystem: xfs Supports d_type: true Using metacopy: false Native Overlay Diff: true userxattr: false Logging Driver: json-file Cgroup Driver: systemd Cgroup Version: 1 Plugins: Volume: local Network: bridge host ipvlan macvlan null overlay Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog Swarm: inactive Runtimes: io.containerd.runc.v2 runc Default Runtime: runc Init Binary: docker-init containerd version: 61f9fd88f79f081d64d6fa3bb1a0dc71ec870523 runc version: v1.1.9-0-gccaecfc init version: de40ad0 Security Options: seccomp Profile: /etc/docker/seccomp.json Kernel Version: 4.18.0-477.27.1.el8_8.x86_64 Operating System: Red Hat Enterprise Linux 8.8 (Ootpa) OSType: linux Architecture: x86_64 CPUs: 24 Total Memory: 125.4GiB Name: platjenagent10.ci28302344.cloud.alfaintra.net ID: 1ca266ec-9d13-4088-ba7f-2000b2d45f15 Docker Root Dir: /var/lib/docker Debug Mode: true File Descriptors: 173 Goroutines: 178 System Time: 2024-08-28T11:23:56.134551161+03:00 EventsListeners: 0 Experimental: true
解决方案
问题根源
核心问题在于:官方gradle镜像的默认Gradle用户缓存目录是/home/gradle/.gradle,而非项目目录下的.gradle。项目目录的.gradle是构建临时目录,Docker在清理中间容器时不会将其内容保留到最终镜像;同时Docker 24.x版本对中间层的清理逻辑更严格,放大了这个问题。
修复方案
切换到Gradle全局缓存目录
修改Dockerfile,直接操作镜像默认的全局缓存目录,确保缓存被保留到最终镜像:FROM gradle:7.6-jdk11 COPY . . # 先拉取依赖缓存,再执行测试 RUN gradle dependencies && gradle test # 验证全局缓存存在 RUN ls -l /home/gradle/.gradle/caches利用Docker BuildKit缓存挂载(CI环境优先)
启用Docker BuildKit后,通过挂载缓存目录,既能在构建时复用缓存提升速度,又能确保最终镜像保留缓存:# syntax=docker/dockerfile:1 FROM gradle:7.6-jdk11 COPY . . # 挂载Gradle全局缓存目录,构建时复用,最终镜像保留缓存 RUN --mount=type=cache,target=/home/gradle/.gradle/caches \ gradle test && ls -l /home/gradle/.gradle/caches RUN ls -l /home/gradle/.gradle/caches合并RUN指令减少中间层
将缓存生成和验证的命令合并到同一个RUN指令,避免中间容器清理导致的缓存丢失:FROM gradle:7.6-jdk11 COPY . . RUN gradle test && ls -l /home/gradle/.gradle/caches && ls -l .gradle/caches
内容的提问来源于stack exchange,提问作者suit
相关产品推荐
相关产品推荐

