java容器化必须用多阶段构建:第一阶段用maven:3.9-eclipse-temurin-17等镜像编译打包,第二阶段用eclipse-temurin:17-jre-alpine等最小jre镜像运行jar,最终镜像仅含jre和jar,剔除maven、jdk工具链、源码等全部编译残留。

Java 应用 Docker 镜像臃肿,根本原因不是代码本身,而是把编译环境(Maven、JDK 全量工具链)和运行环境混在同一个镜像里。多阶段构建不是“高级技巧”,而是 Java 容器化的标准做法——它用两个隔离阶段,让最终镜像只含 JRE + JAR,不带任何编译残留。
第一阶段:用完整构建镜像编译打包
这一阶段只负责生成可运行的 JAR 文件,镜像可以大,但不能留进最终产物。
- 用官方 Maven 镜像(如
maven:3.9-eclipse-temurin-17),它自带 JDK 17 和 Maven,无需额外安装 - 只复制
pom.xml和src,避免把.git、target、IDE 配置等无用文件带入构建上下文 - 推荐先执行
mvn dependency:go-offline,预下载依赖,提升缓存命中率和构建稳定性 - 加
AS builder显式命名阶段,方便第二阶段通过--from=builder引用
第二阶段:用最小化 JRE 镜像运行应用
这是最终交付的镜像,必须轻、稳、兼容。
- 禁用
openjdk:17-jdk或openjdk:17-slim——它们仍是全量 JDK,体积超 400MB - 优先选
eclipse-temurin:17-jre-alpine(约 182MB)或amazoncorretto:17-jre-alpine,兼顾体积与 Spring Boot 兼容性 - Alpine 需补
ca-certificates(HTTPS 调用必需),否则可能报PKIX path building failed - 用
COPY --from=builder精确拷贝 JAR,不复制源码、pom.xml、.m2等任何中间产物
关键细节:别让镜像“看着小,实际跑不起来”
很多团队换了 JRE 镜像后启动失败,不是写法错,而是踩了兼容性坑。
-
ClassNotFoundException(javax.* 或 jakarta.*):部分精简 JRE 移除了 Jakarta EE 模块。Spring Boot 2.7+ 默认使用 jakarta,建议换
eclipse-temurin或amazoncorretto的 JRE 版本 -
UnknownHostException(Alpine DNS 失败):Alpine 默认用 musl libc,DNS 解析行为与 glibc 不同。可在 Dockerfile 中加
RUN echo "hosts: files dns" > /etc/nsswitch.conf修复 -
JVM 内存越界被 OOM Kill:容器内存限制 ≠ JVM 自动适配。务必加 JVM 参数,例如
java -XX:MaxRAMPercentage=75.0 -jar app.jar
配套优化:让构建更快更干净
多阶段是核心,但单靠它还不够。
- 加
.dockerignore文件,排除target/、.git/、logs/、*.iml等,减少上下文传输体积和构建层污染 - 构建时加
--no-cache只在调试阶段用;日常应依赖 Layer 缓存,把COPY pom.xml放在COPY src前,提升依赖层复用率 - 若对体积极致敏感(如边缘部署),可用
jlink构建自定义最小 JRE,但需额外验证模块依赖,适合成熟项目
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











