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-plugin
的go-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镜像构建方案:
手动多阶段构建:
- 编写
Dockerfile
管理依赖和构建过程 - 利用多阶段特性优化缓存和镜像体积
- 编写
Jib插件方案:
- 无需
Dockerfile
,插件自动处理构建步骤 - 简化依赖管理,减少手动配置开销
- 无需
两种方案各有优势:多阶段构建更灵活可控,Jib则更简单粗暴。根据实际需求选择即可。
完整代码示例见GitHub仓库。