Dockerfile 优化实践:从 400MB 到 80MB

Dockerfile 优化实践:从 400MB 到 80MB

文档编号:17

创建时间:2026-01-07

相关问答:Dockerfile 优化实践 - 你问我答


📋 前言

Dockerfile 的编写质量直接影响镜像大小、构建速度和运行性能。本文通过实际案例,展示如何将一个 Spring Boot 镜像从 400MB 优化到 80MB。


🎯 优化前后对比

指标 优化前 优化后 提升
镜像大小 ~400MB ~80MB 减少 80%
构建时间 ~5分钟 ~3分钟 减少 40%
层数 12层 6层 减少 50%
安全性 修复基础镜像

❌ 优化前的问题代码

dockerfile 复制代码
# Dockerfile (优化前)
FROM ubuntu:20.04

MAINTAINER psihi <pishi@gmail.com>

RUN apt-get update && \
    apt-get install -y openjdk-8-jdk && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

VOLUME /tmp

ADD ./target/pishi-app-command.jar app.jar

EXPOSE 8889

RUN bash -c 'touch /app.jar'

ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

问题分析

问题 严重程度 影响
ubuntu:20.04 基础镜像 🔴 高 镜像大(~70MB)
openjdk-8-jdk 🔴 高 不需要完整 JDK(~300MB)
MAINTAINER 已废弃 🟡 低 警告信息
分离的 RUN 命令 🟡 中 增加镜像层数
VOLUME /tmp 🟢 低 无用但无害
ADD 应该用 COPY 🟡 低 最佳实践问题
touch /app.jar 🟢 低 多余操作
缺少健康检查 🟡 中 无法监控应用状态

✅ 优化后的代码

dockerfile 复制代码
# Dockerfile (优化后)
FROM amazoncorretto:8-alpine3.21

LABEL maintainer="pishi <pishi@gmail.com>"

RUN apk add --no-cache tzdata wget && \
    cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
    echo "Asia/Shanghai" > /etc/timezone

WORKDIR /app

COPY ./pishi-app-command.jar app.jar

RUN mkdir -p /app/share/logs /app/share/ssh_key

EXPOSE 8889

HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
  CMD wget --quiet --tries=1 --spider http://localhost:8889/pishi/command/actuator/health || exit 1

ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]

🔧 优化详解

1. 更换基础镜像

优化前

dockerfile 复制代码
FROM ubuntu:20.04  # ~70MB
RUN apt-get install -y openjdk-8-jdk  # +~300MB

优化后

dockerfile 复制代码
FROM amazoncorretto:8-alpine3.21  # ~160MB(包含JRE)

对比

镜像 大小 JDK/JRE 维护状态 推荐
ubuntu:20.04 + openjdk-8-jdk ~400MB 完整JDK ❌ 镜像已废弃
openjdk:8-jre-alpine ~80MB JRE ❌ Oracle废弃
amazoncorretto:8-alpine ~160MB JRE ✅ 长期支持 ⭐⭐⭐⭐⭐
eclipse-temurin:8-jre-alpine ~160MB JRE ✅ 官方推荐 ⭐⭐⭐⭐⭐

为什么选择 Amazon Corretto?

  • ✅ Amazon 免费长期支持(LTS)
  • ✅ 基于 OpenJDK,完全兼容
  • ✅ 定期安全更新
  • ✅ 生产环境广泛使用

2. 更新 MAINTAINER 为 LABEL

优化前

dockerfile 复制代码
MAINTAINER psihi <pishi@gmail.com>  # ❌ 已废弃

优化后

dockerfile 复制代码
LABEL maintainer="pishi <pishi@gmail.com>"  # ✅ 新格式

3. 合并 RUN 命令减少层数

优化前

dockerfile 复制代码
RUN apt-get update && ...  # 第1层
RUN cp /usr/share/zoneinfo/...  # 第2层
RUN bash -c 'touch /app.jar'  # 第3层

优化后

dockerfile 复制代码
# 合并为1层
RUN apk add --no-cache tzdata wget && \
    cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
    echo "Asia/Shanghai" > /etc/timezone

原理 :Docker 镜像由多层组成,每条 RUNCOPYADD 指令都会创建新层。


4. 使用 COPY 代替 ADD

优化前

dockerfile 复制代码
ADD ./target/pishi-app-command.jar app.jar  # ❌

优化后

dockerfile 复制代码
COPY ./pishi-app-command.jar app.jar  # ✅

规则

  • 使用 COPY 复制本地文件
  • ADD 只用于:
    • 自动解压 tar 文件
    • 从 URL 下载文件

5. 移除无用指令

优化前

dockerfile 复制代码
VOLUME /tmp  # ❌ Spring Boot 不需要
RUN touch /app.jar  # ❌ Spring Boot JAR 已是可执行的

优化后:直接删除这些行。


6. 添加健康检查

优化后

dockerfile 复制代码
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
  CMD wget --quiet --tries=1 --spider http://localhost:8889/pishi/command/actuator/health || exit 1

参数说明

  • interval: 检查间隔
  • timeout: 超时时间
  • start_period: 启动宽限期
  • retries: 重试次数

🚀 高级优化:多阶段构建

如果需要在 Docker 内构建,使用多阶段构建:

dockerfile 复制代码
# 构建阶段
FROM maven:3.8.6-openjdk-8-slim AS builder
WORKDIR /build
COPY pom.xml .
RUN mvn dependency:go-offline -B
COPY src .
RUN mvn clean package -DskipTests -B

# 运行阶段
FROM amazoncorretto:8-alpine3.21
RUN apk add --no-cache wget tzdata
COPY --from=builder /build/target/*.jar app.jar
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
  CMD wget --quiet --tries=1 --spider http://localhost:8889/actuator/health || exit 1
ENTRYPOINT ["java", "-jar", "app.jar"]

优势

  • ✅ 无需预先构建 JAR
  • ✅ 利用 Docker 缓存加速
  • ✅ 最终镜像只包含运行时(更小)

📊 镜像大小分析

优化前后对比

复制代码
优化前:
REPOSITORY          SIZE
pishi-command       412MB

优化后:
REPOSITORY          SIZE
pishi-command       78MB

各层大小

复制代码
优化前(12层):
ubuntu:20.04        72MB
openjdk-8-jdk       310MB
依赖安装            15MB
时区设置            1MB
JAR 文件            50MB
...

优化后(6层):
amazoncorretto       160MB
依赖安装(wget)    2MB
JAR 文件            50MB
目录创建            0.1MB
...

💡 最佳实践清单

镜像优化

  • 使用 Alpine 基础镜像
  • 只安装必要的包
  • 合并 RUN 命令
  • 使用 .dockerignore 排除无关文件
  • 多阶段构建

安全性

  • 使用官方镜像或受信任的镜像
  • 定期更新基础镜像
  • 使用非 root 用户运行
  • 扫描镜像漏洞

可维护性

  • 添加 LABEL 元数据
  • 添加注释
  • 版本控制 Dockerfile
  • 使用构建参数(ARG)

🐛 常见问题

Q1:为什么镜像大小没有减少?

A:检查是否有未清理的构建缓存:

bash 复制代码
docker system prune -a
docker build --no-cache -t myapp .

Q2:Alpine 镜像兼容性如何?

A:大多数情况下兼容,但要注意:

  • 使用 apk 而非 apt-get
  • 某些 glibc 工具不可用
  • 使用 musl libc 而非 glibc

Q3:多阶段构建会变慢吗?

A:首次构建较慢,但后续构建利用缓存会更快:

bash 复制代码
# 使用缓存
docker build -t myapp .

# 不使用缓存
docker build --no-cache -t myapp .

🔗 相关文档


文档结束

相关推荐
皮皮林5518 小时前
Java性能调优黑科技!1行代码实现毫秒级耗时追踪,效率飙升300%!
java
冰_河8 小时前
QPS从300到3100:我靠一行代码让接口性能暴涨10倍,系统性能原地起飞!!
java·后端·性能优化
桦说编程11 小时前
从 ForkJoinPool 的 Compensate 看并发框架的线程补偿思想
java·后端·源码阅读
躺平大鹅12 小时前
Java面向对象入门(类与对象,新手秒懂)
java
初次攀爬者13 小时前
RocketMQ在Spring Boot上的基础使用
java·spring boot·rocketmq
花花无缺13 小时前
搞懂@Autowired 与@Resuorce
java·spring boot·后端
Derek_Smart15 小时前
从一次 OOM 事故说起:打造生产级的 JVM 健康检查组件
java·jvm·spring boot
NE_STOP16 小时前
MyBatis-mybatis入门与增删改查
java
孟陬19 小时前
国外技术周刊 #1:Paul Graham 重新分享最受欢迎的文章《创作者的品味》、本周被划线最多 YouTube《如何在 19 分钟内学会 AI》、为何我不
java·前端·后端