如何使用 Docker 多阶段构建优化 Java SpringBoot 镜像体积大小

文章导读
对于 Java SpringBoot 项目,最推荐的做法是使用 Docker 多阶段构建,将编译环境与运行环境分离,适用于大多数生产部署场景。
📋 目录
  1. A 命令速用版
  2. B 核心优化点解析
  3. C 效果验证:体积对比实测
  4. D 常见坑与排查
  5. E 参考来源
A A

对于 Java SpringBoot 项目,最推荐的做法是使用 Docker 多阶段构建,将编译环境与运行环境分离,适用于大多数生产部署场景。

先说结论:多阶段构建能有效移除构建工具依赖,显著减小最终镜像体积,适合需要控制传输成本和启动速度的生产环境。

  • 先定位:确认当前镜像体积及构成,识别冗余层
  • 先做:编写多阶段 Dockerfile 分离构建与运行环境,配置非 root 用户
  • 再验证:对比构建前后的镜像大小和容器启动日志

命令速用版

下面是一个经过安全加固和体积优化的多阶段构建 Dockerfile 模板,你可以直接参考修改:

# 第一阶段:构建
FROM maven:3.9-openjdk-17 AS build
WORKDIR /app
# 优化缓存:先复制依赖文件
COPY pom.xml .
RUN mvn dependency:go-offline
# 复制源代码
COPY src ./src
RUN mvn clean package -DskipTests

# 第二阶段:运行
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
# 安装时区数据
RUN apk add `--no-cache` tzdata
ENV TZ=Asia/Shanghai
# 创建非 root 用户
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
# 复制构建产物
COPY `--from`=build /app/target/*.jar app.jar
RUN chown -R appuser:appgroup /app
USER appuser
ENTRYPOINT ["java", "-jar", "app.jar"]

核心优化点解析

相比传统构建,该模板做了以下关键改进:

如何使用 Docker 多阶段构建优化 Java SpringBoot 镜像体积大小
  • 基础镜像精简:运行阶段使用 eclipse-temurin:17-jre-alpine 替代 JDK 镜像,仅包含运行所需的 JRE,体积更小。
  • 依赖层缓存:单独复制 pom.xml 并下载依赖,确保源代码变动时不失效依赖层缓存。
  • 安全加固:创建 appuser 并切换用户,避免容器以 root 权限运行。
  • 时区配置:安装 tzdata 并设置 ENV TZ,防止日志时间偏差。

效果验证:体积对比实测

构建完成后,使用以下命令验证优化效果:

# 查看镜像大小
docker images | grep your-image-name
# 查看镜像分层
docker history your-image-id

典型体积对比:

  • 优化前:使用 openjdk:17-jdk 单阶段构建,镜像体积通常在 500MB 以上。
  • 优化后:使用多阶段构建 + JRE Alpine 镜像,体积通常可降至 200MB 左右,减少约 60%。

常见坑与排查

  • 权限拒绝 (Permission Denied):如果启动报错,检查是否已切换非 root 用户且文件归属权正确。确保执行了 chown 命令。
  • 时区不对:日志时间相差 8 小时,确认是否安装 tzdata 并设置了 ENV TZ=Asia/Shanghai。
  • 类版本不支持:构建阶段 JDK 版本高于运行阶段 JRE 版本会导致报错,请保持版本一致(如均为 17)。
  • 缓存失效:确保 pom.xml 在 COPY src 之前复制,否则每次代码变动都会重新下载依赖。

参考来源

  • Docker 官方文档 - Multi-stage builds: https://docs.docker.com/build/building/multi-stage/
  • Spring Boot 官方指南 - Dockerizing a Spring Boot Application: https://spring.io/guides/topicals/spring-boot-docker/