使用 multi-stage builds 优化 Docker 镜像

发布: (2025年12月19日 GMT+8 02:08)
2 min read
原文: Dev.to

Source: Dev.to

Fala, devs! Hoje vim compartilhar com vocês uma dica de como reduzir o tamanho das suas imagens Docker em projetos Java + Maven: multi‑stage builds!

O problema que eu tinha

No início do meu aprendizado com Docker, era assim que eu construía minhas imagens:

FROM maven:3.9.10-eclipse-temurin-21

WORKDIR /app

COPY . .

RUN mvn clean package -DskipTests

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "target/app.jar"]

O problema é que essas poucas linhas geram uma imagem de mais de 600 MB! Isso acontece porque muitas coisas que não são necessárias em tempo de execução acabam sendo incluídas na imagem final.

A solução

Multi‑stage builds permitem usar múltiplas instruções FROM no Dockerfile, cada uma com uma base diferente, e compartilhar artefatos entre os estágios. Assim, podemos escolher apenas o que for necessário para a execução, reduzindo o tamanho da imagem final.

Um Dockerfile para um projeto Maven com Java 21 usando multi‑stage fica assim:

# ---------- Build stage ----------
FROM maven:3.9.10-eclipse-temurin-21-alpine AS build

WORKDIR /app

# Copia apenas o pom.xml e resolve dependências (cacheável)
COPY pom.xml .
RUN mvn dependency:go-offline -B

# Copia o código fonte e compila
COPY src ./src
RUN mvn clean package -DskipTests

# ---------- Runtime stage ----------
FROM eclipse-temurin:21-jre-alpine

WORKDIR /app

# Copia apenas o JAR gerado no estágio de build
COPY --from=build /app/target/*.jar app.jar

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "app.jar"]

Entendendo cada parte

Processo de build

FROM maven:3.9.10-eclipse-temurin-21-alpine AS build

Utiliza a imagem do Maven com JDK 21 baseada em Alpine (mais leve) e nomeia o estágio como build

COPY pom.xml .
RUN mvn dependency:go-offline -B

Copiamos apenas o pom.xml e baixamos as dependências. Se o pom.xml não mudar, essa camada fica em cache, acelerando builds subsequentes。

COPY src ./src
RUN mvn clean package -DskipTests

Depois copiamos o código fonte e compilamos o projeto, pulando os testes。

A cartada final

FROM eclipse-temurin:21-jre-alpine

Usamos uma imagem Alpine contendo apenas o JRE (não o JDK), suficiente para executar a aplicação。

COPY --from=build /app/target/*.jar app.jar

Copiamos apenas o JAR gerado no estágio build para a nova imagem, descartando tudo o que não é necessário em tempo de execução。

O resultado

Com esses ajustes, uma imagem que antes tinha cerca de 800 MB passa para aproximadamente 280 MB, uma redução de quase 65 %

$ docker images
IMAGE                ID           DISK USAGE   CONTENT SIZE   EXTRA
multi-stage-build:latest   339813c13178   283MB        73.3MB
single-stage-build:latest  0aadd77f8d9c   834MB        258MB

E por hoje é isso. Espero que esse exemplo tenha te ajudado. 🚀

Referências

Back to Blog

相关文章

阅读更多 »

Maven 的内部

介绍 今天我浪费了两小时的宝贵时间。就是这样。 这一切都是因为 Maven https://maven.apache.org/,在我看来,它很奇特。 一切都与……有关