51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

在 Docker 中构建多模块 Maven 项目

1、概览 {#1概览}

本文将带你了解如何利用 Docker 的多阶段构建功能高效地为多模块 Maven 项目构建 Docker 镜像,,以充分利用 Docker 的缓存机制。

然后,还会介绍 Google Jib Maven 插件,用于在没有 DockerfileDocker 的情况下构建 Docker 镜像。

2、多模块 Maven 项目 {#2多模块-maven-项目}

多模块 Maven 应用由不同功能的独立模块组成。Maven 通过管理依赖关系来构建应用,并将这些模块组装成一个可部署的单元。

在本文的代码示例中,我们将使用一个包含两个 Maven 模块的基本 Spring Boot 项目,这两个模块分别代表应用程序的 Domain 和 API。

Maven 项目的结构如下:

+-- parent
   +-- api
   |   `-- src
   |   `-- pom.xml
   +-- domain
   |   `-- src
   |   `-- pom.xml
    `-- pom.xml

查看父模块的 pom.xml 文件,就会发现它继承了 spring-boot-starter-parent,并包含了 domainapi 模块:

<project>
    <groupId>com.baeldung.docker-multi-module-maven</groupId>
    <artifactId>parent</artifactId>
    <packaging>pom</packaging>
    <version>0.0.1-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.2</version>
        <relativePath />
    </parent>

    <!-- 模块 -->
    <modules>
        <module>api</module>
        <module>domain</module>
    </modules>

    <!--  other configuration  -->
</project>

此外,我们还遵循了简洁架构原则,确保所有源码的依赖方向都是正确的。简而言之,确保 api 模块依赖于 module 模块,而不是相反。

3、多阶段 Docker 构建 {#3多阶段-docker-构建}

Docker 中的多阶段构建允许我们在单个 Docker 文件中使用多个 FROM 指令来创建更小、更高效的镜像。每个阶段都可用于不同的目的,如编译代码或打包应用,只有最后阶段才会包含在最终镜像中。

例如,我们的示例可以使用三个阶段:提取依赖、构建应用程序和准备运行时环境。

创建包含这三个不同部分的 Dockerfile

# 预取依赖
FROM maven:3.8.5-openjdk-17 AS DEPENDENCIES

# 构建 jar
FROM maven:3.8.5-openjdk-17 AS BUILDER

# 准备运行时环境
FROM openjdk:17-slim

3.1、预取依赖项 {#31预取依赖项}

DEPENDENCIES 阶段将为我们的应用预先获取和缓存 Maven 依赖项。

先选择 Maven 镜像,然后复制三个 pom.xml 文件:

FROM maven:3.8.5-openjdk-17 AS DEPENDENCIES

WORKDIR /opt/app
COPY api/pom.xml api/pom.xml
COPY domain/pom.xml domain/pom.xml
COPY pom.xml .

然后,需要使用 maven-dependency-plugin 及其 go-offline goal 来解析和下载 pom.xml 文件中指定的所有依赖。此外,还通过指定 "-B" 选项以非交互模式运行命令,并通过 "-e" 提示所有错误:

RUN mvn -B -e org.apache.maven.plugins:maven-dependency-plugin:3.1.2:go-offline -DexcludeArtifactIds=domain

最后还添加了 excludeArtifactIds 属性,以防止 Maven 下载特定的组件。在本例中,它排除了 domain 组件。因此,domain JAR 将在本地构建,而不是从 Repository 中获取。

这个命令确保在下一个阶段运行构建过程时,所有依赖项都将在本地可用,无需再次下载。

3.2、构建镜像 {#32构建镜像}

要构建镜像,首先需要确保所有必要的依赖都已预先获取,并且源代码可用。在 BUILDER 阶段,我们首先要从 DEPENDENCIES 阶段复制必要的资源:

FROM maven:3.8.5-openjdk-17 AS BUILDER

WORKDIR /opt/app
COPY --from=DEPENDENCIES /root/.m2 /root/.m2
COPY --from=DEPENDENCIES /opt/app/ /opt/app
COPY api/src /opt/app/api/src
COPY domain/src /opt/app/domain/src

接下来,运行 mvn clean install 来编译代码并构建 domainapi JAR 文件。由于测试可能已经在之前运行过了,我们可以使用 -DskipTests 跳过测试来加快编译过程:

RUN mvn -B -e clean install -DskipTests

3.3、准备运行环境 {#33准备运行环境}

Dockerfile 的最后阶段,我们要为应用设置最基本的运行环境。

将选择应用将要运行的基础镜像,复制前一阶段的 JAR 文件,并定义启动应用的入口点:

FROM openjdk:17-slim

WORKDIR /opt/app
COPY --from=BUILDER /opt/app/api/target/*.jar /app.jar
EXPOSE 8080

ENTRYPOINT ["java", "-jar", "/app.jar"]

3.4、运行应用 {#34运行应用}

最后,我们就可以构建并运行镜像了。还可以添加 from-dockerfile 标签来区分该镜像:

docker build -t baeldung-demo:from-dockerfile .

docker run -p 8080:8080 baeldung-demo:from-dockerfile

此时,请求 localhost:8080/api/countries,就可以获取到响应。

如你所见,多阶段 Dockerfile 通过将构建依赖与最终运行环境隔离开来,简化了依赖管理。此外,它还能帮助我们减少最终镜像的大小,因为它只复制了构建阶段的必要工件,从而提高了效率和安全性。

4、使用 Jib 构建项目 {#4使用-jib-构建项目}

我们还可以使用 Jib 等专用工具构建 Docker 镜像。Jib Maven 插件是一种工具,可直接从我们的 Maven 构建中为 Java 应用程序构建优化的 Docker 镜像,而无需 DockerfileDocker 守护进程。

Jib 需要配置几个关键属性:

  • Java 基础镜像
  • 生成的 Docker 镜像的名称
  • 应用的入口
  • 暴露的端口

maven-jib-plugin 添加到 API 模块的 pom.xml 中:

<plugin>
    <groupId>com.google.cloud.tools</groupId>
    <artifactId>jib-maven-plugin</artifactId>
    <version>3.4.0</version>
    <configuration>
        <from>
            <image>openjdk:17-slim</image>
        </from>
        <to>
            <image>baeldung-demo:from-jib</image>
        </to>
        <container>
            <mainClass>com.baeldung.api.Application</mainClass>
            <ports>
                <port>8080</port>
            </ports>
        </container>
    </configuration>
</plugin>

之后,就可以使用 Maven 来构建镜像:

mvn compile jib:dockerBuild

最后,Jib 成功地构建了 Docker 镜像,现在我们可以使用 docker run 命令运行应用程序了:

docker run -p 8080:8080 baeldung-demo:from-jib

5、总结 {#5总结}

本文介绍了如何使用 Docker 的多阶段构建功能为多模块的 Maven 项目构建 Docker 镜像,以及如何使用 Jib Maven 插件来构建 Docker 镜像,而无需 Dockerfile。


Ref:https://www.baeldung.com/docker-maven-build-multi-module-projects

赞(3)
未经允许不得转载:工具盒子 » 在 Docker 中构建多模块 Maven 项目