Otimização de imagens Docker é um passo essencial para um deployment rápido e seguro. Uma das ferramentas mais poderosas para isso é o multi-stage builds. Essa técnica permite criar imagens enxutas e limpas, sem dependências desnecessárias, facilitando a manutenção e acelerando o processo de build.
Neste artigo, vamos explorar em detalhes o que são os multi-stage builds no contexto do Docker, quais problemas eles resolvem e como funcionam na prática. Você aprenderá como essa técnica pode reduzir significativamente o tamanho das imagens, melhorar a segurança, aumentar a performance em pipelines de CI/CD e simplificar o gerenciamento de dependências. Também vamos mostrar exemplos reais de uso com diferentes linguagens e tecnologias — de Go e Node.js a Python e Java. Além disso, você receberá recomendações sobre quando aplicar essa abordagem e quais erros evitar.
O que é Multi-Stage Builds?
Multi-stage build é uma abordagem onde um único Dockerfile contém múltiplos estágios de construção (stages), cada um podendo usar uma imagem base diferente. Apenas os artefatos necessários são copiados para a imagem final, descartando todas as dependências intermediárias (como compiladores, ferramentas de teste, etc.).
Isso permite:
- Reduzir o tamanho da imagem final;
- Evitar a inclusão de dados sensíveis ou ferramentas de desenvolvimento em produção;
- Usar um único Dockerfile para build e runtime.
Exemplo: Build de um app em Go
Abordagem comum:
WORKDIR /app
COPY . .
RUN go build -o myapp
CMD ["./myapp"]
Essa imagem contém o toolchain completo do Go, desnecessário em produção.
Solução com multi-stage:
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp
# Stage de runtime
FROM alpine
COPY --from=builder /app/myapp /myapp
ENTRYPOINT ["/myapp"]
Resultado: a imagem final tem apenas alguns megabytes e inclui somente o binário executável.
Por que isso é importante?
Vantagens do multi-stage builds:
- Imagens limpas: somente binários e arquivos necessários são incluídos;
- Velocidade: imagens menores são mais rápidas para baixar e iniciar;
- Segurança: menos ferramentas = menos vulnerabilidades potenciais;
- Versatilidade: aplicável à maioria das linguagens e frameworks.
Exemplos de uso
Node.js
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Produção
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/index.js"]
Python (com dependências C compiladas)
FROM python:3.12 AS builder
WORKDIR /app
COPY . .
RUN pip install --user -r requirements.txt
# Final
FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY . .
ENV PATH=/root/.local/bin:$PATH
CMD ["python", "main.py"]
Quando usar multi-stage builds?
Use quando:
- Seu app exige build ou compilação (Go, Rust, Java, C++);
- Você quer reduzir o tamanho da imagem de produção;
- É necessário isolar ferramentas de build do ambiente de execução;
- A segurança é uma prioridade — menos dependências, menos riscos.
Conclusão
Multi-stage builds são uma forma simples, mas poderosa de otimizar imagens Docker. Eles permitem separar o processo de build do de execução, criando imagens leves, seguras e limpas.
Se você quer acelerar seus builds, reduzir custos de infraestrutura e melhorar a segurança, multi-stage builds devem fazer parte do seu kit de ferramentas DevOps.
Docker e Serverspace
Se você está começando com Docker ou deseja aprofundar seus conhecimentos, confira a Base de Conhecimento da Serverspace.
Lá você encontrará diversos tutoriais detalhados, guias e conteúdos práticos sobre Docker e seus principais componentes — desde os conceitos básicos até tópicos avançados como Docker Compose, otimização de imagens, integração com CI/CD e uso em ambientes de nuvem. O conteúdo é constantemente atualizado e atende desde iniciantes até engenheiros DevOps experientes.