1. 简介

随着越来越多企业转向容器化和虚拟化架构,Docker 已成为现代软件开发流程中不可或缺的一环。Spring Boot 2.3 版本引入了一项非常实用的新特性:无需编写 Dockerfile 即可轻松构建 Docker 镜像

本文将带你掌握使用 Spring Boot 构建 Docker 镜像的主流方式,重点分析不同方案的优劣和适用场景,帮助你在实际项目中做出更优选择。


2. 传统 Docker 构建方式

最经典的方式是通过 Dockerfile 手动构建镜像。以下是一个典型的示例:

FROM openjdk:17-jdk-alpine
EXPOSE 8080
ARG JAR_FILE=target/demo-app-1.0.0.jar
ADD ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

使用 docker build 命令即可完成镜像构建。这种方式虽然通用,但存在两个明显问题:

启动性能差
Spring Boot 的 fat jar(可执行 JAR)在容器中启动时,JVM 需要从归档中加载所有类,影响冷启动速度。

镜像层优化不足
Docker 镜像采用分层机制,但 fat jar 把所有第三方依赖和应用代码打包在一个层。哪怕只改一行代码,整个层都需重新构建,严重拖慢 CI/CD 流程。

💡 踩坑提示:在 CI 环境频繁构建时,这种“全量重建”会显著增加构建时间和资源消耗。

理想做法是将 JAR 解包(explode),让依赖和应用代码各自独立成层,充分利用 Docker 的缓存机制。Spring Boot 提供了更优雅的解决方案,我们接下来就看看。


3. 使用 Buildpacks(推荐)

Buildpacks 是一种无需 Dockerfile 即可构建镜像的工具,它能自动分析项目类型并注入所需运行时依赖。例如,给它一个 Spring Boot 的 JAR 包,它会自动添加合适的 JVM 和启动逻辑。

Spring Boot 原生支持 Maven 和 Gradle 构建镜像。以 Maven 为例:

./mvnw spring-boot:build-image

构建过程中你会看到类似输出:

[INFO] Building jar: target/demo-0.0.1-SNAPSHOT.jar
...
[INFO] Building image 'docker.io/library/demo:0.0.1-SNAPSHOT'
...
[INFO]  > Pulling builder image 'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3' 100%
...
[INFO]     [creator]     ===> DETECTING
[INFO]     [creator]     5 of 15 buildpacks participating
[INFO]     [creator]     paketo-buildpacks/bellsoft-liberica 2.8.1
[INFO]     [creator]     paketo-buildpacks/executable-jar    1.2.8
[INFO]     [creator]     paketo-buildpacks/apache-tomcat     1.3.1
[INFO]     [creator]     paketo-buildpacks/dist-zip          1.3.6
[INFO]     [creator]     paketo-buildpacks/spring-boot       1.9.1
...
[INFO] Successfully built image 'docker.io/library/demo:0.0.1-SNAPSHOT'
[INFO] Total time:  44.796 s

关键点解析:

  • ✅ 使用 Paketo 构建器(Cloud Native Buildpacks 实现)
  • ✅ 自动识别项目为 Spring Boot 类型,注入 Java 运行时和启动器
  • ✅ 生成的镜像天然分层,启动更快,体积更小

⚠️ 首次构建较慢(需下载构建器和缓存层),但后续构建飞快:

...
[INFO]     [creator]     Reusing layer 'paketo-buildpacks/executable-jar:class-path'
[INFO]     [creator]     Reusing layer 'paketo-buildpacks/spring-boot:web-application-type'
...
[INFO] Successfully built image 'docker.io/library/demo:0.0.1-SNAPSHOT'
...
[INFO] Total time:  10.591 s

优势总结

  • 无需维护 Dockerfile
  • 自动优化镜像结构
  • 支持主流 CI/CD 平台(如 GitHub Actions、GitLab CI)
  • 安全性高(使用官方可信构建器)

💬 简单粗暴地说:spring-boot:build-image 几乎是开箱即用的最佳实践。


4. 分层 JAR(Layered JAR)方案

如果你已有成熟的 Dockerfile 流程,或需要更精细控制镜像构建,Spring Boot 也支持通过 分层 JAR 实现高效构建。

4.1 分层 JAR 原理

传统 fat jar 结构如下:

org/
  springframework/
    boot/
  loader/
...
BOOT-INF/
  classes/      # 应用代码
  lib/          # 第三方依赖

分层 JAR 多了一个 layers.idx 文件,定义了各目录对应的层:

- "dependencies":
  - "BOOT-INF/lib/"
- "spring-boot-loader":
  - "org/"
- "snapshot-dependencies":
- "application":
  - "BOOT-INF/classes/"
  - "BOOT-INF/classpath.idx"
  - "BOOT-INF/layers.idx"
  - "META-INF/"

Spring Boot 默认提供四层:

  • dependencies:稳定第三方依赖
  • snapshot-dependencies:快照依赖
  • resources:静态资源
  • application:应用代码(最常变动)

核心价值:只有变更的层才会重新构建,大幅提升 CI 效率。


4.2 生成分层 JAR

Maven 配置如下:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <layers>
            <enabled>true</enabled>
        </layers>
    </configuration>
</plugin>

执行 mvn package 后生成的 JAR 即支持分层操作。


4.3 查看与解包分层

查看分层结构:

java -Djarmode=layertools -jar demo-0.0.1.jar list

解包到当前目录:

java -Djarmode=layertools -jar demo-0.0.1.jar extract

执行后会生成 dependencies/, application/ 等目录。


4.4 构建 Docker 镜像

结合 Dockerfile 使用分层:

FROM openjdk:17-jdk-alpine as builder
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract

FROM openjdk:17-jdk-alpine
COPY --from=builder dependencies/ ./
COPY --from=builder snapshot-dependencies/ ./
COPY --from=builder spring-boot-loader/ ./
COPY --from=builder application/ ./
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]

构建时每一行 COPY 都会形成独立镜像层:

Step 6/10 : COPY --from=builder dependencies/ ./
 ---> 2c631b8f9993
Step 7/10 : COPY --from=builder snapshot-dependencies/ ./
 ---> 26e8ceb86b7d
Step 8/10 : COPY --from=builder spring-boot-loader/ ./
 ---> 6dd9eaddad7f
Step 9/10 : COPY --from=builder application/ ./
 ---> dc80cc00a655

优势

  • 可复用现有 Dockerfile
  • 灵活控制镜像结构
  • 与 CI 缓存策略完美配合

5. 总结

方案 优点 缺点 推荐场景
Buildpacks 开箱即用,无需 Dockerfile,自动优化 首次构建慢,定制性略低 新项目、快速上线
Layered JAR + Dockerfile 完全可控,兼容现有流程 需维护 Dockerfile 已有容器化流程的项目

✅ **建议优先使用 spring-boot:build-image**,简单、安全、高效。
⚠️ 若需精细控制(如多阶段构建、自定义基础镜像),再考虑分层 JAR 方案。

所有示例代码已上传至 GitHub:https://github.com/example-tutorials/docker-spring-boot
进阶推荐:结合 Jib 实现更高效的 Java 镜像构建。


原始标题:Creating Docker Images with Spring Boot