1. 概述

本文将介绍如何高效地为多模块Maven项目构建Docker镜像。首先我们会利用多阶段Docker构建技术,充分发挥Docker的缓存机制。

接着探讨另一种方案:使用Google的Jib Maven插件。这个工具能创建优化的Docker镜像,无需编写Dockerfile或依赖Docker守护进程。

2. 多模块Maven项目

多模块Maven应用将不同功能拆分为独立模块。Maven通过管理依赖关系,将这些模块组装成单一可部署单元。

本文示例采用一个基础Spring Boot项目,包含两个Maven模块:domain(领域模块)和api(接口模块)。项目结构如下:

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

父模块的pom.xml继承自spring-boot-starter-parent,并包含两个子模块:

<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>

    <!--  其他配置  -->
</project>

遵循整洁架构原则:api模块依赖domain模块,但反之不成立。

3. 多阶段Docker构建

多阶段构建允许在单个Dockerfile中使用多个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. 预拉取依赖

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-plugingo-offline目标解析并下载所有依赖。通过-B启用非交互模式,-e显示所有错误:

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

⚠️ 关键点:excludeArtifactIds参数阻止Maven下载domain模块的依赖,强制该模块在本地构建而非从仓库获取。

此操作确保后续构建阶段所有依赖已本地缓存,无需重复下载。

3.2. 构建镜像

构建阶段需确保依赖已预拉取且源码可用。**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编译代码并构建JAR文件。假设测试已通过,使用-DskipTests加速构建:

RUN mvn -B -e clean install -DskipTests

3.3. 准备运行环境

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. 运行应用

构建并运行镜像(添加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构建项目

Jib Maven插件是专门构建Java应用Docker镜像的工具,无需Dockerfile或Docker守护进程

需配置四个关键属性:

  • Java基础镜像
  • 目标镜像名称
  • 应用入口点
  • 暴露端口

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

构建完成后运行应用:

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

5. 总结

本文介绍了两种多模块Maven项目的Docker镜像构建方案:

  1. 手动多阶段构建

    • 编写Dockerfile管理依赖和构建过程
    • 利用多阶段特性优化缓存和镜像体积
  2. Jib插件方案

    • 无需Dockerfile,插件自动处理构建步骤
    • 简化依赖管理,减少手动配置开销

两种方案各有优势:多阶段构建更灵活可控,Jib则更简单粗暴。根据实际需求选择即可。

完整代码示例见GitHub仓库


原始标题:How to Build Multi-Module Maven Projects in Docker | Baeldung