Maven docker cache dependencies

10 浏览
0 Comments

Maven docker cache dependencies

我正在尝试使用Docker来自动化Maven构建。我想要构建的项目需要将所有依赖项下载大约20分钟,所以我尝试构建一个Docker镜像来缓存这些依赖项,但似乎没有保存下来。我的Dockerfile是这样的:

FROM maven:alpine
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
ADD pom.xml /usr/src/app
RUN mvn dependency:go-offline

镜像构建成功,并且确实下载了所有内容。然而,生成的镜像与基本的`maven:alpine`镜像大小相同,所以似乎没有在镜像中缓存这些依赖项。当我尝试使用镜像来`mvn compile`时,会再次花费整整20分钟重新下载一遍所有内容。

有没有可能构建一个可以缓存我的依赖项的Maven镜像,这样每次使用镜像进行构建时就不再需要重新下载?

我运行以下命令:

docker build -t my-maven .
docker run -it --rm --name my-maven-project -v "$PWD":/usr/src/mymaven -w /usr/src/mymaven my-maven mvn compile

我的理解是,在Docker构建过程中,无论`RUN`做了什么,都会成为最终镜像的一部分。

0
0 Comments

问题原因:在使用的基础镜像中,存在一个父镜像定义了VOLUME "$USER_HOME_DIR/.m2",导致在构建过程中所有文件都被写入到$USER_HOME_DIR/.m2,但由于这个目录被定义为一个卷,所以这些文件不会与容器镜像一起保留。

解决方法:由于Docker目前没有任何方法来注销该卷定义,因此需要构建一个单独的maven镜像,而不是使用官方的maven镜像。可以使用Docker卷,并告诉maven使用不同的路径作为maven仓库缓存,方法如下-Dmaven.repo.local=/mvn/.m2nrepo/repository

注意:这些镜像不再挂载~/.m2作为一个卷,相关链接如下:github.com/carlossg/docker-maven/issues/11 github.com/carlossg/docker-maven/issues/36,自2017年12月以来,该卷声明已不再存在,详情请参见github.com/carlossg/docker-maven/pull/57

0
0 Comments

自Docker v18.03版本开始,可以使用BuildKit来替代之前提到的卷,BuildKit允许挂载缓存以在构建之间持久存在,并且可以避免每次下载相应的.m2/repository内容。

假设Dockerfile在项目的根目录中:

# syntax = docker/dockerfile:1.0-experimental
FROM maven:3.6.0-jdk-11-slim AS build
COPY . /home/build
RUN mkdir /home/.m2
WORKDIR /home/.m2
USER root
RUN --mount=type=cache,target=/root/.m2 mvn -f /home/build/pom.xml clean compile

target=/root/.m2将缓存挂载到maven镜像Dockerfile中指定的位置。

构建时可以运行以下命令:

DOCKER_BUILDKIT=1 docker build --rm --no-cache .

有关BuildKit的更多信息可以在此处找到:[https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/syntax.md](https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/syntax.md)。

这个问题是否适用于没有WSL2的Windows环境?

我自己没有在Windows上尝试过。但是根据[此处](https://github.com/moby/buildkit/issues/616)的说明,Windows上使用BuildKit的过程并不是很顺利。

0
0 Comments

Maven Docker 缓存依赖项的问题出现的原因是,当尝试启动 Docker 镜像构建时,pom.xml 文件通常不会有任何更改,只会有其他源代码的更改。在这种情况下,可以进行以下操作:

1. 添加 pom.xml 文件。

2. 然后执行 mvn verify --fail-never 命令,它将下载 Maven 依赖项。

3. 添加所有源代码文件,并开始编译(mvn package)。

pom.xml 文件发生变化或首次运行此脚本时,Docker 将按照 1 -> 2 -> 3 的顺序执行。当 pom.xml 文件没有变化时,Docker 将跳过步骤 1 和 2,并直接执行步骤 3。

这个简单的技巧在许多其他的包管理情况下(如 Gradle、Yarn、NPM、PIP)也可以使用。

然而,根据其他评论和答案的建议,还应考虑使用 mvn dependency:resolvemvn dependency:go-offline 命令。

值得注意的是,dependency:resolve 命令不会下载插件。而且不幸的是,dependency:resolve-plugins 命令也会漏掉生命周期插件。因此,建议使用 dependency:go-offline 命令。

根据我的经验,dependency:go-offline 命令下载的内容要比 mvn verify --fail-never 命令少得多,而且它们都无法下载我项目所需的所有内容。

当构建推送到 Docker Hub 注册表的 Docker 镜像时,使用 --fail-never 不是一个好主意,特别是通过自动构建。

这个解决方案是一个聪明而优雅的解决方法,可以与 Docker 缓存一起使用,以实现预期的行为。

0