最终Dockerfile

#syntax=docker/dockerfile:1.2
FROM maven:3.8.6-openjdk-8-slim as MAVEN_BUILD
COPY . /build/
WORKDIR /build/

RUN --mount=type=cache,target=/root/.m2,id=maven-cache \
  mvn clean package -Dmaven.test.skip=true --quiet

FROM openjdk:8-jdk-alpine
COPY --from=MAVEN_BUILD /build/target/*.jar /data/app.jar
WORKDIR /data/
EXPOSE 80
ENV TZ=Asia/Shanghai
ENTRYPOINT ["java","-Xmx512m","-jar","app.jar"]

构建命令

DOCKER_BUILDKIT=1 docker build -t myapp .

RUN --mount=type=cache,target=/root/.m2,id=maven-cache

挂载缓存目录必须在RUN里面执行,后面直接跟构建命令。
DOCKER_BUILDKIT=1 临时使用buildkit方式构建。(不须要修改docker配置文件)

注意这里建议设定 id 参数,因为不提供 id 参数的话,id 的默认值为 target 的值,这样一旦我们以后想修改 taget 路径,就很麻烦。
指定 id 后,target 的路径随意修改扔不会影响结果。

参数

–mount=type=cache 参数说明

id

id 设置一个标志,以便区分缓存。

target

(必填项) 缓存的挂载目标文件夹。

ro,readonly

只读,缓存文件夹不能被写入。

sharing

有 sharedprivatelocked 值可供选择。sharing 设置当一个缓存被多次使用时的表现,由于 BuildKit 支持并行构建,当多个步骤使用同一缓存时(同一 id)会发生冲突。shared 表示多个步骤可以同时读写,private 表示当多个步骤使用同一缓存时,每个步骤使用不同的缓存,locked 表示当一个步骤完成释放缓存后,后一个步骤才能继续使用该缓存。

from

缓存来源(构建阶段),不填写时为空文件夹。

source

来源的文件夹路径。

验证缓存

Dockerfile

[root@saas /]# cat Dockerfile 
#syntax=docker/dockerfile:1.2
FROM busybox:1.36.0

RUN --mount=type=cache,target=/cache,id=cache \
  echo cache >> /cache/logs.txt && cat /cache/logs.txt

第一次执行

[root@saas /]# DOCKER_BUILDKIT=1 docker build --progress=plain -t myapp .
#2 [internal] load .dockerignore
#2 transferring context: 2B done
#2 DONE 0.0s

#1 [internal] load build definition from Dockerfile
#1 transferring dockerfile: 194B done
#1 DONE 0.0s

#3 resolve image config for docker.io/docker/dockerfile:1.2
#3 DONE 0.0s

#4 docker-image://docker.io/docker/dockerfile:1.2
#4 CACHED

#5 [internal] load build definition from Dockerfile
#5 transferring dockerfile: 194B done
#5 DONE 0.0s

#6 [internal] load metadata for docker.io/library/busybox:1.36.0
#6 DONE 0.0s

#7 [stage-0 1/2] FROM docker.io/library/busybox:1.36.0
#7 CACHED

#8 [stage-0 2/2] RUN --mount=type=cache,target=/cache,id=cache   echo cache...
#8 0.155 cache
#8 DONE 0.2s

#9 exporting to image
#9 exporting layers
#9 exporting layers done
#9 writing image sha256:66935ee5d7dd5f05ea633915ed16fc7a1cb640768e896dcc7b0c4cea4ec3bfd6 done
#9 naming to docker.io/library/myapp done
#9 DONE 0.0s

注意#8 里面有一个0.155 cache 就是咱们写入共享缓存目录内文件的内容。
修改Dockersfile文件。

[root@saas /]# cat Dockerfile 
#syntax=docker/dockerfile:1.2
FROM busybox:1.36.0

RUN --mount=type=cache,target=/cache,id=cache \
  echo cache1 >> /cache/logs.txt && cat /cache/logs.txt

修改echo内容。再次构建。

[root@saas /]# DOCKER_BUILDKIT=1 docker build --progress=plain -t myapp .
......
#8 [stage-0 3/3] RUN --mount=type=cache,target=/cache,id=cache   echo cache...
#8 0.155 cache
#8 0.155 cache1
#8 DONE 0.2s
......

这时#8步骤输出的cache是2行。第2行是第2次构建写入的内容。说明已经使用到刚刚的共享缓存了。

缓存位置和清理缓存

# cache默认会在
/var/lib/docker/overlay2/26位随机字符/diff/
# 使用命令清理
docker builder prune

相关参考资料:

Docker Buildkit(新增 --mount、–security、–network 等特性)

怎么把一个Java应用打包成Docker镜像

为什么 docker build 不显示命令的任何输出?
https://www.likecs.com/ask-675687.html

Docker Hub Build Mounts RUN --mount=…
https://hub.docker.com/r/docker/dockerfile

Docker Docs Garbage collection
https://docs.docker.com/build/cache/garbage-collection/