【问题标题】:Quarkus: Try to cache maven dependencies using multistage docker buildQuarkus:尝试使用多阶段 docker build 缓存 maven 依赖项
【发布时间】:2020-06-03 19:04:30
【问题描述】:

我有一个简单的 Quarkus 应用程序,我尝试使用以下多级 Dockerfile 构建它。

FROM maven:3-jdk-8-slim AS build
WORKDIR /build
# Download Dependencies
COPY pom.xml .
RUN mvn dependency:go-offline

# Build App
COPY src/ /build/src/
RUN mvn -Dmaven.test.skip=true package -Dcheckstyle.skip

# Stage 2 : create the docker final image
FROM adoptopenjdk:8-jre-openj9 AS runtime
COPY --from=build /build/target/*-runner.jar /app/app.jar
COPY --from=build /build/target/lib/* /app/lib/

WORKDIR /app
RUN chgrp -R 0 /app &&\
    chmod g=u /app
USER 1001

EXPOSE 8080
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app/app.jar"]

和 pom.xml

<?xml version="1.0"?>
<project
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
  xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.test</groupId>
  <artifactId>booking-mgr</artifactId>
  <version>1.0-SNAPSHOT</version>
  <properties>
    <compiler-plugin.version>3.8.1</compiler-plugin.version>
    <maven.compiler.parameters>true</maven.compiler.parameters>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <quarkus-plugin.version>1.1.1.Final</quarkus-plugin.version>
    <quarkus.platform.artifact-id>quarkus-universe-bom</quarkus.platform.artifact-id>
    <quarkus.platform.group-id>io.quarkus</quarkus.platform.group-id>
    <quarkus.platform.version>1.1.1.Final</quarkus.platform.version>
    <surefire-plugin.version>2.22.1</surefire-plugin.version>
  </properties>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>${quarkus.platform.group-id}</groupId>
        <artifactId>${quarkus.platform.artifact-id}</artifactId>
        <version>${quarkus.platform.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.10</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-resteasy</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-junit5</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>io.rest-assured</groupId>
      <artifactId>rest-assured</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-resteasy-jsonb</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-smallrye-openapi</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-smallrye-reactive-messaging-kafka</artifactId>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-maven-plugin</artifactId>
        <version>${quarkus-plugin.version}</version>
        <executions>
          <execution>
            <goals>
              <goal>build</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>${compiler-plugin.version}</version>
      </plugin>
      <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>${surefire-plugin.version}</version>
        <configuration>
          <systemProperties>
            <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
          </systemProperties>
        </configuration>
      </plugin>
    </plugins>
  </build>
  <profiles>
    <profile>
      <id>native</id>
      <activation>
        <property>
          <name>native</name>
        </property>
      </activation>
      <build>
        <plugins>
          <plugin>
            <artifactId>maven-failsafe-plugin</artifactId>
            <version>${surefire-plugin.version}</version>
            <executions>
              <execution>
                <goals>
                  <goal>integration-test</goal>
                  <goal>verify</goal>
                </goals>
                <configuration>
                  <systemProperties>
                    <native.image.path>
                      ${project.build.directory}/${project.build.finalName}-runner
                    </native.image.path>
                  </systemProperties>
                </configuration>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>
      <properties>
        <quarkus.package.type>native</quarkus.package.type>
      </properties>
    </profile>
  </profiles>
</project>

构建工作正常,它下载 maven 依赖项,然后创建 .jar 并在最终容器中运行 .jar。但是,如果我更改了源代码中的某些内容并保持 pom.xml 不变,则会再次下载依赖项。看来mvn dependency:go-offline 没有下载所有依赖。

有没有办法以这种方式加速 docker 构建?例如,我对 Spring Boot 做同样的事情,在那里一切都很好。

感谢您的帮助。

【问题讨论】:

  • 你运行了哪个命令来构建你的镜像?
  • 使用docker build .或在docker-compose中使用docker-compose up --build

标签: maven docker quarkus


【解决方案1】:

您的 pom.xml 和 src 文件夹位于构建上下文中(命令中的点)。 如果您更改 src 中的文件,那么您会更改构建上下文,从而使 COPY 缓存无效。

Docker build is not using cache

【讨论】:

  • 我认为这不是问题所在。我在 docker build 中看到缓存层用于以下步骤。 Step 4/14 : RUN mvn dependency:go-offline ---&gt; Using cache ---&gt; 6e9c65b87c29 之后在 package 步骤中再次下载依赖项。
【解决方案2】:

简单来说,你可以将 Dockerfile 一分为二,比如builder-base.dockerfilefinal.dockerfile。然后,创建一个目录builder-base 并将pom.xml 移动到builder-base

目录结构:

.
+-- builder-base
|   +-- pom.xml
|-- src
|-- builder-base.dockerfile
|-- final.dockerfile

final.dockerfile 中是:

FROM java-builder AS build

# Build App
COPY src/ /build/src/
RUN mvn -Dmaven.test.skip=true package -Dcheckstyle.skip

# Stage 2 : create the docker final image
FROM adoptopenjdk:8-jre-openj9 AS runtime
COPY --from=build /build/target/*-runner.jar /app/app.jar
COPY --from=build /build/target/lib/* /app/lib/

WORKDIR /app
RUN chgrp -R 0 /app &&\
    chmod g=u /app
USER 1001

EXPOSE 8080
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app/app.jar"]

首先,将此代码放入builder-base.dockerfile

FROM maven:3-jdk-8-slim 
WORKDIR /build
# Download Dependencies
COPY pom.xml .
RUN mvn dependency:go-offline

所以,首先,你应该构建一个名为“java-builder”的镜像

docker build -t java-builder -f builder.dockerfile ./builder-base

现在,您可以使用以下命令编译源代码:

docker build -t app -f final.dockerfile .

final.dockerfile中的基础镜像是java-builder,如果不重新构建镜像,可以随时使用缓存创建docker最终镜像。

【讨论】:

  • 你用 quarkus 试过了吗?它不起作用,所以我认为这不是 docker 的问题,而是与 maven 依赖关系有关:go-offline。好像不是所有的依赖都下载好了。
  • 你能提供一个我可以重现问题的演示吗?运行docker build -t java-builder -f builder.dockerfile ./builder-base后,java-build镜像构建完成,所有依赖下载完毕。
  • 只要改一下源码,再运行docker build -t app -f final.dockerfile .,就会看到又下载了一些依赖。
【解决方案3】:

我发现mvn package 可以完成这项工作。 现在我使用:

COPY pom.xml .
RUN mvn --batch-mode \
        --quiet \
        --errors \
        dependency:go-offline \
        package

COPY src ./src
RUN mvn --batch-mode \
        --quiet \
        --errors \
        --define maven.test.skip=true \
        --define java.awt.headless=ture \
        clean package

看起来很奇怪,但没有错误。

【讨论】:

    猜你喜欢
    • 2022-12-18
    • 2018-06-06
    • 1970-01-01
    • 2019-03-24
    • 2017-07-01
    • 2020-03-19
    • 2019-05-10
    • 2022-11-25
    • 1970-01-01
    相关资源
    最近更新 更多