DEV Community

Yuri Peixinho
Yuri Peixinho

Posted on • Edited on

Multi-Stage Build (Dockerfile)

É uma abordagem avançada no Docker que utiliza múltiplos estágios (stages) dentro de um único Dockerfile. Suas vantanges são:

Sem o Multi-Stage a imagem pode ficar cheia de arquivos que não são necessários para rodar a aplicação em produção, como ferramentas de complicação, dependências usadas apenas no build e arquivos temporários. Com o Multi-Stage, esses arquivos não entram na imagem final

O que são stages?

A ideia do Multi-Stage Build é dividir o Dockerfile em múltiplos estágios (stages), onde cada estágio tem um propósito específico.

Cada estágio tem um propósito diferente:

  1. Build Stage (Compilação): Responsável por compilar o código e gerar os arquivos finais.
  2. Intermediate Stages (Intermediários - opcional): Pode ser usado para testes, minificação, otimizações.
  3. Final Stage (Runtime/Execução): Apenas os arquivos essenciais são copiados e a aplicação roda com uma imagem menor.

Cada estágio é identificado pelo comando FROM, e podemos copiar arquivos entre eles usando COPY --from=<estágio>.

Dockerfile sem Multi-Stage Build (Imagem pesada)

1. Criando o Dockerfile

# Usa a imagem do SDK do .NET (grande)
FROM mcr.microsoft.com/dotnet/sdk:8.0 
# Define o diretório de trabalho
WORKDIR /app 
# Copia todos os arquivos do projeto para dentro do contêiner
COPY . . 
# Compila a aplicação e gera os arquivos de saída
RUN dotnet publish -c Release -o /out 
# Define o diretório de trabalho para os arquivos compilados
WORKDIR /out 
# Define o comando de entrada quando o contêiner for iniciado
ENTRYPOINT ["dotnet", "MinhaApi.dll"]
Enter fullscreen mode Exit fullscreen mode

2. Construindo a imagem

docker build -t minhaapi:sem-multi-stage .
Enter fullscreen mode Exit fullscreen mode
  • Baixar a imagem do SDK .NET
  • Copiar os arquivos para dentro do contêiner
  • Compilar o código
  • Criar a imagem final

Problema: Essa imagem fica grande porque contém o SDK inteiro, que só é necessário para compilar, não para rodar a API.

Rodando o contêiner

docker run -p 8080:80 minhaapi:sem-multi-stage
Enter fullscreen mode Exit fullscreen mode

A API vai rodar na porta 8080. Mas o contêiner está pesado (+1GB).

Dockerfile com Multi-Stage Build (Imagem otimizada)

Agora, vamos ver a versão otimizada que gera uma imagem menor e mais eficiente.

# Base para runtime (imagem mínima)
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 8080

# Estágio de build (compila o código-fonte)
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["MinhaApi/MinhaApi.csproj", "MinhaApi/"]
RUN dotnet restore "MinhaApi/MinhaApi.csproj"
COPY . .
WORKDIR "/src/MinhaApi"
RUN dotnet build -c Release -o /app/build

# Estágio intermediário (rodando testes)
FROM build AS test
WORKDIR /src
RUN dotnet test --no-restore --verbosity normal

# Estágio de publicação (gera os arquivos finais)
FROM build AS publish
RUN dotnet publish "MinhaApi.csproj" -c Release -o /app/publish /p:UseAppHost=false

# Estágio final (imagem pronta para produção)
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "MinhaApi.dll"]

Enter fullscreen mode Exit fullscreen mode

Multi-Stage Build vs. Docker Tradicional

Característica Docker Normal Multi-Stage Build
Tamanho da Imagem Grande, pois inclui dependências de compilação e ferramentas extras Menor, pois só mantém o necessário na imagem final
Etapas do Build Tudo acontece em um único estágio Divide em múltiplos estágios, reutilizando artefatos
Segurança Possui mais ferramentas e arquivos desnecessários na imagem final Apenas o essencial é mantido, reduzindo superfície de ataque
Complexidade do Dockerfile Simples, mas menos otimizado Um pouco mais complexo, mas mais eficiente
Performance no Deploy Mais lenta devido ao tamanho maior da imagem Mais rápida, pois a imagem final é menor

👈🏻 Voltar leitura

Top comments (0)