多阶段构建的核心是分离编译打包与运行服务:构建阶段用完整工具链(如maven:3.8-eclipse-temurin-17)下载依赖、跳过测试、生成jar;运行阶段仅用轻量镜像(如eclipse-temurin:17-jre-slim)复制jar和配置,剔除所有构建工具,实现体积缩减(600mb→70–150mb)与攻击面最小化。

多阶段构建的核心就是把“编译打包”和“运行服务”拆成两个独立阶段,用不同镜像、不同权限、不同依赖来完成各自任务,最终只把运行必需的文件复制进轻量镜像里。
明确两个阶段的分工
构建阶段负责源码编译、依赖下载、测试跳过、JAR 打包,需要完整 JDK 和 Maven/Gradle;运行阶段只保留 JRE、应用 JAR、必要配置,不带任何构建工具或源码。
- 构建阶段推荐使用
maven:3.8-eclipse-temurin-17或gradle:8-jdk17这类带完整工具链的镜像 - 运行阶段优先选
eclipse-temurin:17-jre-slim(Debian 基础,兼容性好)或eclipse-temurin:17-jre-alpine(体积更小,注意 musl libc 兼容性) - 避免用
openjdk:17这类含 JDK 的镜像作运行环境——它自带 javac、jstack 等工具,纯属冗余
编写分阶段 Dockerfile
关键在于用 AS builder 命名第一阶段,并在第二阶段用 COPY --from=builder 精确提取产物。
- Maven 项目示例中,
RUN mvn dependency:go-offline -B放在COPY pom.xml后,能复用构建缓存,加快后续构建 - 务必跳过测试:
mvn package -DskipTests或gradle build -x test,防止测试失败中断构建流程 - JAR 路径要核对清楚:Maven 默认在
target/xxx.jar,Gradle 在build/libs/xxx.jar,写错会导致运行阶段复制失败
控制镜像体积与安全边界
分离环境不只是为了瘦身,更是为了最小化攻击面。
- 运行阶段镜像里没有 shell(如 Alpine 默认无 bash)、没有包管理器(如 apt/apk)、不开放 root 权限,可大幅降低被入侵风险
- 如果对安全性要求极高,可进一步选用
gcr.io/distroless/java17-debian11,它连 shell 都不提供,只留 JVM 和应用 - 不要在运行阶段做
RUN apt-get update或安装额外工具——这违背了“不可变镜像”原则,也破坏了环境一致性
验证分离是否生效
构建完成后,用 docker images 查看镜像大小变化;再用 docker run -it --rm <image> sh</image> 尝试进入容器,确认运行镜像中确实没有 mvn、javac、gcc 等构建工具。
- 典型效果:传统单阶段镜像常超 600MB,多阶段后可压到 90–150MB(slim)或 70–100MB(alpine)
- 若发现运行镜像仍很大,检查是否误把整个
/app目录 COPY 过去,应只复制 JAR 文件和必要配置
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











