Dan*_*ous 28 java maven docker dockerfile
我正在尝试使用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
我的理解是,RUN在docker构建过程中的任何内容都会成为生成的图像的一部分.
Kim*_*Kim 27
通常,pom.xml文件没有变化,但是当您尝试启动docker映像构建时,其他src代码会发生变化.在这种情况下,你可以这样做:
供参考:
FROM maven:3-jdk-8
ENV HOME=/home/usr/app
RUN mkdir -p $HOME
WORKDIR $HOME
# 1. add pom.xml only here
ADD pom.xml $HOME
# 2. start downloading dependencies
RUN ["/usr/local/bin/mvn-entrypoint.sh", "mvn", "verify", "clean", "--fail-never"]
# 3. add all source code and start compiling
ADD . $HOME
RUN ["mvn", "package"]
EXPOSE 8005
CMD ["java", "-jar", "./target/dist.jar"]
所以关键是:
添加pom.xml文件.
然后mvn verify --fail-never它,它将下载maven依赖项.
然后添加所有源文件,并开始编译(mvn package).
当您的更改pom.xml或您第一次运行此脚本时,docker将执行1  - > 2  - > 3.当pom.xml文件中没有更改时,docker将跳过步骤1,2并直接执行3.
这个简单的技巧可以用在许多其他包管理环境中.
从那时Docker v18.03起,您可以使用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 docs 中的指定位置。
对于构建,您可以运行以下命令:
DOCKER_BUILDKIT=1 docker build --rm --no-cache  .   
可以在此处找到有关 BuildKit 的更多信息。
我不认为这里的其他答案是最佳的。例如,mvn verifyanswer 执行以下阶段,并且不仅仅是解决依赖关系:
验证 - 验证项目是否正确并且所有必要的信息都可用
compile - 编译项目的源代码
测试 - 使用合适的单元测试框架测试编译的源代码。这些测试不应该要求打包或部署代码
包 - 获取编译后的代码并将其打包为其可分发格式,例如 JAR。
验证 - 对集成测试的结果进行任何检查,以确保满足质量标准
如果您只想解决依赖关系,则不需要运行所有这些阶段及其相关目标。
如果只想解决依赖关系,可以使用dependency:go-offline目标:
FROM maven:3-jdk-12
WORKDIR /tmp/example/
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src/ src/
RUN mvn package
事实证明,我用作基础的图像具有定义的父图像
VOLUME "$USER_HOME_DIR/.m2"
请参阅:https://github.com/carlossg/docker-maven/blob/322d0dff5d0531ccaf47bf49338cb3e294fd66c8/jdk-8/Dockerfile
结果是在构建期间,所有文件都被写入$USER_HOME_DIR/.m2,但由于它应该是卷,因此这些文件都不会与容器映像一起保留.
目前在Docker中没有任何方法可以取消注册该卷定义,因此有必要构建一个单独的maven图像,而不是使用官方的maven图像.
@Kim 最接近,但还没有完全到位。我不认为添加--fail-never是正确的,即使通过它完成了工作。
该verify命令会导致执行很多插件,这是一个问题(对我而言) - 我认为当我只想安装依赖项时,它们不应该执行!我还有一个多模块构建和一个 javascript 子构建,因此这进一步使设置复杂化。
但是只运行verify是不够的,因为如果你install在下面的命令中运行,将会使用更多的插件——这意味着需要下载更多的依赖——否则 maven 拒绝下载它们。相关阅读:Maven:构建生命周期简介
您基本上必须找到禁用每个插件的属性并一个一个地添加它们,这样它们就不会破坏您的构建。
WORKDIR /srv
# cache Maven dependencies
ADD cli/pom.xml /srv/cli/
ADD core/pom.xml /srv/core/
ADD parent/pom.xml /srv/parent/
ADD rest-api/pom.xml /srv/rest-api/
ADD web-admin/pom.xml /srv/web-admin/
ADD pom.xml /srv/
RUN mvn -B clean install -DskipTests -Dcheckstyle.skip -Dasciidoctor.skip -Djacoco.skip -Dmaven.gitcommitid.skip -Dspring-boot.repackage.skip -Dmaven.exec.skip=true -Dmaven.install.skip -Dmaven.resources.skip
# cache YARN dependencies
ADD ./web-admin/package.json ./web-admin/yarn.lock /srv/web-admin/
RUN yarn --non-interactive --frozen-lockfile --no-progress --cwd /srv/web-admin install
# build the project
ADD . /srv
RUN mvn -B clean install
但是有些插件不是那么容易跳过 - 我不是 Maven 专家(所以我不知道为什么它忽略了 cli 选项 - 它可能是一个错误),但以下内容按预期工作 org.codehaus.mojo:exec-maven-plugin
<project>
    <properties>
        <maven.exec.skip>false</maven.exec.skip>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.3.2</version>
                <executions>
                    <execution>
                        <id>yarn install</id>
                        <goals>
                            <goal>exec</goal>
                        </goals>
                        <phase>initialize</phase>
                        <configuration>
                            <executable>yarn</executable>
                            <arguments>
                                <argument>install</argument>
                            </arguments>
                            <skip>${maven.exec.skip}</skip>
                        </configuration>
                    </execution>
                    <execution>
                        <id>yarn run build</id>
                        <goals>
                            <goal>exec</goal>
                        </goals>
                        <phase>compile</phase>
                        <configuration>
                            <executable>yarn</executable>
                            <arguments>
                                <argument>run</argument>
                                <argument>build</argument>
                            </arguments>
                            <skip>${maven.exec.skip}</skip>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
请注意明确<skip>${maven.exec.skip}</skip>-其他插件(既不接从CLI PARAMS这件事,但没有这一项-Dmaven.exec.skip=true,也不-Dexec.skip=true由本身的工作)
希望这可以帮助
缓存maven依赖有两种方式:
执行“mvn verify”作为容器执行的一部分,而不是构建,并确保从卷挂载 .m2。
这是有效的,但它不适用于云构建和多个构建从属
使用“依赖项缓存容器”,并定期更新它。方法如下:
一种。创建一个 Dockerfile 来复制 pom 并构建离线依赖项:
FROM maven:3.5.3-jdk-8-alpine
WORKDIR /build
COPY pom.xml .
RUN mvn dependency:go-offline
湾 定期(例如每晚)将其构建为“Deps:latest”
C。创建另一个 Dockerfile 以在每次提交时实际构建系统(最好使用多阶段) - 并确保它是 FROM Deps。
使用此系统,您将拥有快速、可重构的构建,并且具有足够好的缓存。