多阶段构建剥离JDK编译环境,仅保留JRE运行时+应用jar,是Java镜像瘦身最有效稳妥手段;单靠Dockerfile调整即可缩减70%+体积,避免使用含完整JDK的镜像如openjdk:17-jdk-slim。

直接结论:用多阶段构建剥离 JDK 编译环境,只保留 JRE 或 jdk-jre 运行时 + 应用 jar,是 Java 镜像瘦身最有效、最稳妥的手段。不改代码、不换框架,单靠 Dockerfile 调整就能压掉 70%+ 体积。
为什么 Java 镜像动辄 500MB+?
典型单阶段构建的 Dockerfile 常这样写:
FROM openjdk:17-jdk-slim COPY target/app.jar . CMD ["java", "-jar", "app.jar"]
问题就出在 openjdk:17-jdk-slim —— 它带完整 JDK(含 javac、javadoc、debug 工具链),而运行时根本用不到。这个镜像本身已超 400MB,再叠加上应用 jar,很容易突破 500MB。
更糟的是,如果还顺手 RUN apt-get update && apt-get install -y curl vim,缓存没清、工具留着,体积只会更大,攻击面也更宽。
立即学习“Java免费学习笔记(深入)”;
Java 多阶段构建的标准写法
核心思路:第一阶段用完整 JDK 编译/打包;第二阶段用极简运行时(如 eclipse/jre:17-jre 或 amazoncorretto:17-jre-alpine)加载 jar。
- 第一阶段必须用
AS builder显式命名,否则--from=builder会报错 - 第二阶段避免使用
openjdk:xx-jdk或openjdk:xx-slim,它们仍是 JDK 全量版 - 优先选
jre后缀镜像(如amazoncorretto:17-jre-alpine),体积通常 scratch,Java 应用依赖 glibc 或 ca-certificates,直接跑会No such file or directory
示例 Dockerfile:
FROM maven:3.9-openjdk-17 AS builder WORKDIR /app COPY pom.xml . RUN mvn dependency:go-offline -B COPY src ./src RUN mvn package -DskipTests FROM amazoncorretto:17-jre-alpine RUN apk --no-cache add ca-certificates WORKDIR /app COPY --from=builder /app/target/app.jar . CMD ["java", "-jar", "app.jar"]
容易踩的坑:JRE 镜像不是都“能跑”
看似只换了个基础镜像,但实际运行可能失败,常见原因:
-
ClassNotFoundException或NoClassDefFoundError:某些jre镜像精简过度,缺javax.*模块(尤其 Spring Boot 2.7+ 默认移除了 Jakarta EE 8 的旧包)。解决:换用amazoncorretto或eclipse-temurin的jre版本,它们兼容性更好 -
Caused by: java.net.UnknownHostException:Alpine 镜像默认无 DNS 解析支持。解决:加RUN apk --no-cache add bind-tools或改用debian:jre类镜像(体积略大但省心) -
Invalid or corrupt jarfile:COPY 路径写错,比如COPY --from=builder /app/target/*.jar .匹配到多个 jar。解决:固定文件名,或用mvn package -DfinalName=app统一输出名
还能再压?试试分层缓存 + 构建参数
多阶段只是起点,配合以下调整可再省 10–20MB:
- 把
pom.xml和mvn dependency:go-offline单独作为一层,利用 Docker 缓存——只要依赖不变,后续构建跳过整个下载过程 - 用
maven:3.9-openjdk-17-slim替代maven:3.9-openjdk-17,构建阶段也能小几十 MB - Spring Boot 用户可启用
spring-boot-maven-plugin的layout=ZIP,生成可执行 jar 后用java -Djarmode=layertools -jar app.jar extract拆 layer,再 COPY/dependencies等目录实现更细粒度复用(适合 CI 高频构建场景)
最终镜像大小取决于你选的 JRE 基础镜像:Alpine 类通常 80–120MB,Debian 类约 180–220MB。相比原始 500MB+,70% 缩减是常态。真正难的不是“怎么写”,而是确认你的应用在精简 JRE 下是否真能稳定运行——这点必须本地和 CI 都跑通测试,不能只看 docker run 启动成功。


















