核心是分离编译与运行环境:构建阶段用maven:3.9-eclipse-temurin-17拉依赖、编译、跳过测试、生成jar;运行阶段用eclipse-temurin:17-jre-alpine仅装jre、复制jar、执行java-jar,彻底剔除javac、mvn等冗余工具。
java 项目用 docker 多阶段构建分离 maven 编译与 jre 运行,核心是让两个环境完全解耦:第一阶段只管编译打包,第二阶段只管启动服务,中间不传递任何冗余文件或工具。
明确两个阶段的职责边界
构建阶段(builder)只做四件事:拉依赖、编译源码、跳过测试、生成 JAR;运行阶段(runtime)只做三件事:装最小 JRE、复制 JAR、执行 java -jar。两者镜像不同、权限不同、文件系统隔离。
- 构建阶段必须用带完整 JDK 和 Maven 的镜像,例如 maven:3.9-eclipse-temurin-17 或 gradle:8-jdk17
- 运行阶段严禁使用含 jdk 的镜像(如 openjdk:17-jdk-slim),应选带 jre 后缀的轻量镜像,比如 eclipse-temurin:17-jre-alpine 或 amazoncorretto:17-jre-alpine
- 最终镜像里不能出现
javac、mvn、src/、pom.xml、.m2/等任何构建痕迹
编写标准两阶段 Dockerfile
关键在于用 AS builder 显式命名第一阶段,并在第二阶段通过 COPY --from=builder 精确提取产物,路径必须核对准确。
- 第一阶段先 COPY pom.xml,再 RUN mvn dependency:go-offline -B —— 利用缓存加速后续构建
- 再 COPY src/,然后 RUN mvn package -DskipTests —— 跳过测试防止中断,JAR 默认输出到
target/*.jar - 第二阶段基于 jre 镜像,RUN apk add --no-cache ca-certificates(Alpine 必加证书支持 HTTPS)
- COPY --from=builder /app/target/myapp.jar /app/app.jar —— 注意路径别写成
target/*.jar(通配符在 COPY 中不可靠)
避开常见运行失败问题
换用精简 JRE 后服务起不来,多数不是配置错,而是基础环境缺失或兼容性没对齐。
- ClassNotFoundException:某些 Alpine jre 移除了 Jakarta EE 模块,Spring Boot 3.x 项目建议换 eclipse-temurin:17-jre-slim(Debian 基础)或 amazoncorretto:17-jre-alpine
- UnknownHostException:Alpine 默认 DNS 解析异常,加一句 RUN echo "hosts: files dns" > /etc/nsswitch.conf 即可修复
- No such file or directory:若 JAR 内部调用了 JNI 或本地库,distroless 或 Alpine 不支持,应回退到 eclipse-temurin:17-jre-slim
进阶:用 jlink 定制更小 JRE(可选)
如果对体积有极致要求(目标
- RUN jdeps --print-module-deps app.jar 得到依赖模块列表,例如
java.base,java.logging,java.xml - RUN jlink --add-modules java.base,java.logging,java.xml --strip-debug --compress=2 --output /customjre
- 再把 /customjre 和 JAR 一起打包,体积可压到 110–140MB 区间
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











