多阶段构建通过分离编译与运行环境,仅将jar包复制至精简jre镜像,剔除jdk、maven等冗余组件,使spring boot镜像从1.2gb降至约200mb,同时缩小攻击面、加快冷启动。

Java 应用 Docker 镜像体积大,核心原因在于 JDK 运行时臃肿、构建依赖(如 Maven)和中间产物(如 target/)被一并打包进最终镜像。多阶段构建正是为解决这个问题而生——它允许你在不同阶段使用不同基础镜像,只把真正运行时需要的文件复制到最终镜像中,彻底剥离编译工具链和源码。
第一阶段:用 SDK 镜像编译代码
选用带完整 JDK 和构建工具(如 Maven、Gradle)的镜像作为构建阶段基础,比如 maven:3.8-openjdk-17-slim 或 gradle:8-jdk17。这一阶段负责拉取依赖、编译源码、执行测试、生成可执行 JAR(或 native image)。关键点是:不关心最终镜像大小,只确保构建成功。
- 推荐显式指定
-Dmaven.repo.local=/tmp/.m2避免缓存污染 - 加
--no-snapshot-updates加速依赖解析(尤其 CI 环境) - 用
mvn clean package -DskipTests跳过测试可显著缩短构建时间(测试应单独跑)
第二阶段:用 JRE 或精简 JDK 镜像运行
这是瘦身的关键一步。放弃包含 javac、javadoc、jshell 等开发工具的完整 JDK,改用仅含 JVM 和核心类库的运行时镜像:
-
eclipse/jre:17-jre-focal(基于 Ubuntu,轻量但非 Alpine) -
amazoncorretto:17-jre-alpine(Alpine + Corretto,约 60MB) -
adoptopenjdk/openjdk17:jre-hotspot-nightly-ubuntu(已归档,建议迁移到 Temurin) - 更极致选择:
eclipse/temurin:17-jre-jammy或library/eclipse-temurin:17-jre-alpine-jre
注意:JRE 镜像不包含 java 命令以外的开发工具,但足够运行 Spring Boot fat jar 或普通 jar。
只复制必要文件,拒绝“全盘拷贝”
多阶段构建的价值不在分阶段,而在精准搬运。最终镜像里只需三样东西:JVM、应用 jar、启动脚本(如有)。不要 COPY . /app,而是明确指定:
COPY --from=build /app/target/myapp.jar /app.jar- 若需配置文件,单独 COPY:
COPY --from=build /app/src/main/resources/application.yml /config/application.yml - 避免复制
target/classes或target/maven-archiver等中间目录
Spring Boot 项目可利用 spring-boot-maven-plugin 的 repackage 目标生成 fat jar,直接运行 java -jar app.jar,无需解压,进一步减少层干扰。
进阶技巧:启用分层缓存与 JLink 定制运行时
对体积极度敏感的场景(如边缘设备),可进一步压缩:
- 用
jlink构建最小化 JDK:在构建阶段执行jlink --add-modules java.base,java.logging,... --output /jre-min,再将定制 JRE 复制到最终镜像 - 结合
BuildKit启用高级缓存:DOCKER_BUILDKIT=1 docker build --progress=plain .,提升重复构建效率 - Spring Boot 3+ 用户可尝试
native-image(GraalVM),生成静态二进制,镜像可小至 20MB,但需适配反射、JNI 等限制
多数业务系统用 JRE + fat jar 已能将镜像从 800MB+ 压到 100MB 内;启用 jlink 或 native 可进一步压到 50MB 以下,但需权衡构建复杂度和兼容性。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











