Como implementar multi-stage builds em imagens de produção: guia prático para produção
Aprenda a implementar multi-stage builds Docker para separar compilação e runtime, reduzir imagens de produção e fortalecer a segurança dos containers.
Max Alex

Imagens Docker grandes acumulam compiladores, gerenciadores de pacotes e arquivos temporários que não deveriam chegar ao ambiente produtivo. Os multi-stage builds Docker resolvem esse problema ao separar as etapas de compilação, teste e execução no mesmo Dockerfile.
Neste guia, você vai criar imagens de produção menores, com menos componentes expostos e mais simples de distribuir em pipelines e registries.
O que são multi-stage builds no Docker
Um multi-stage build é um Dockerfile com mais de uma instrução FROM. Cada FROM inicia um estágio independente, com sua própria imagem base, ferramentas e arquivos.
Normalmente, o primeiro estágio reúne tudo o que a aplicação precisa para compilar ou empacotar: Node.js, Maven, GCC, dependências de desenvolvimento e testes. O último estágio contém somente o runtime e os artefatos necessários para executar a aplicação.
A instrução COPY --from=nome-do-estagio permite copiar arquivos selecionados entre estágios. Assim, dependências de compilação não precisam fazer parte da imagem distribuída para produção.
Por exemplo, uma aplicação front-end pode ser compilada com uma imagem completa do Node.js e ter apenas a pasta dist copiada para uma imagem enxuta do Nginx.
Por que usar multi-stage builds em imagens de produção
O principal benefício é reduzir o tamanho da imagem final. Menos dados para baixar, armazenar e transferir tornam builds e deployments mais rápidos, especialmente quando a equipe trabalha com múltiplos ambientes ou autoscaling.
A abordagem também reduz a superfície de ataque. Ferramentas como compiladores, npm, Maven e arquivos de cache ficam no estágio de build, em vez de permanecerem disponíveis no container em produção. Esse cuidado complementa boas práticas de segurança em containers.
Além disso, a separação torna as responsabilidades explícitas: um estágio gera o artefato; outro o executa. Isso facilita revisões de Dockerfile e reduz a chance de promover arquivos desnecessários ao registry.
Como planejar os estágios do Dockerfile
Antes de escrever o Dockerfile, liste o que é necessário para compilar, testar e executar a aplicação. A pergunta central é simples: quais arquivos e bibliotecas realmente precisam existir quando o container iniciar?
Em uma API, um desenho comum inclui os estágios builder, test e runtime. O builder instala dependências e gera o artefato; o estágio de teste valida o resultado; o runtime recebe somente o artefato aprovado e suas dependências essenciais.
Nomeie os estágios com AS, escolha imagens base adequadas para cada responsabilidade e evite copiar o projeto inteiro para a imagem final. Em especial, diferencie dependências de desenvolvimento das necessárias em execução.
Também vale definir desde o início quais diretórios devem ser ignorados pelo contexto de build, como .git, logs locais, caches, arquivos de ambiente e dependências geradas na máquina do desenvolvedor.
Implementando um multi-stage build passo a passo
O exemplo abaixo representa uma aplicação Node.js que gera arquivos estáticos em dist. O primeiro estágio instala as dependências e executa o build. O segundo usa uma imagem de runtime e recebe apenas o resultado.
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:alpine AS runtime
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]O estágio builder nunca é enviado como imagem final quando esse Dockerfile é construído normalmente. A imagem resultante é baseada no Nginx e contém apenas os arquivos compilados em dist.
Para aplicações que precisam de servidor próprio, o estágio final deve declarar um WORKDIR, executar com um USER sem privilégios quando a imagem permitir e definir um CMD claro. O objetivo é que a imagem final tenha somente o necessário para iniciar o serviço.
Construa e execute localmente para validar o fluxo:
docker build -t minha-aplicacao:local .
docker run --rm -p 8080:80 minha-aplicacao:localExemplos de multi-stage builds para linguagens populares
Node.js
Para aplicações front-end, copie apenas os arquivos compilados para Nginx ou outro servidor estático. Em APIs, instale dependências de produção no estágio apropriado e não leve ferramentas de build, testes ou documentação para o runtime.
Python
Em Python, o builder pode gerar wheels ou preparar um ambiente virtual. A imagem final deve receber apenas as dependências instaladas e o código necessário para iniciar o serviço. Essa separação é particularmente útil ao padronizar containers Python em produção.
Java
Use Maven ou Gradle no estágio de build para gerar o arquivo JAR. Depois, copie somente o JAR para uma imagem com o JRE compatível. Dessa forma, o runtime não precisa carregar o gerenciador de build nem o código-fonte completo.
Go
Go é um caso especialmente favorável: o builder compila um binário e a imagem final pode conter somente esse binário e os arquivos indispensáveis. Verifique dependências dinâmicas, certificados e configuração de rede antes de optar por uma base muito mínima.
Erros comuns ao criar imagens multi-stage
Um erro recorrente é copiar todo o diretório do builder para o runtime. Isso leva node_modules, caches, código-fonte e arquivos temporários para a imagem final, anulando boa parte do benefício.
Prefira cópias específicas, como COPY --from=builder /app/dist ... ou COPY --from=builder /app/target/app.jar .... Revise também as permissões do arquivo copiado, principalmente se o container final usar um usuário sem privilégios.
Outro problema é não usar .dockerignore. Sem ele, arquivos locais desnecessários entram no contexto enviado ao daemon Docker, aumentando o tempo de build e podendo expor informações indevidas.
Não grave segredos, chaves privadas ou arquivos .env dentro da imagem. Variáveis sensíveis devem ser fornecidas pelo mecanismo de configuração do ambiente e nunca incorporadas em uma camada do Dockerfile.
Por fim, teste o runtime de verdade. Uma imagem mínima pode falhar se bibliotecas do sistema, certificados, fuso horário ou arquivos estáticos necessários não tiverem sido incluídos.
Como validar e medir a imagem final
Meça o resultado antes de publicar. Compare a versão anterior e a nova com docker image ls; isso confirma se a redução de tamanho esperada ocorreu.
docker image ls
docker history minha-aplicacao:local
docker run --rm minha-aplicacao:localUse docker history para identificar camadas excessivas e inspecione a imagem final para confirmar que ferramentas de build não permaneceram nela. Em seguida, execute um teste de smoke: suba o container, verifique o endpoint de saúde ou a rota principal e confirme os logs de inicialização.
No CI/CD, automatize build, testes, análise de vulnerabilidades e publicação. Use tags imutáveis, como uma versão ou o identificador do commit, para que seja possível rastrear exatamente qual imagem foi implantada.
Uma validação útil é tentar iniciar a imagem em um ambiente limpo. Se ela depender de arquivos externos não documentados ou de comportamento da máquina do desenvolvedor, o problema aparecerá antes do deploy.
Checklist para colocar multi-stage builds em produção
- Separe build, teste e runtime quando isso fizer sentido para a aplicação.
- Copie para o estágio final somente artefatos e dependências essenciais.
- Use uma imagem base adequada e mantenha versões críticas controladas.
- Inclua um arquivo
.dockerignorebem definido. - Não inclua segredos, caches, código desnecessário ou ferramentas de compilação na imagem final.
- Execute o processo com usuário sem privilégios sempre que possível.
- Teste a inicialização e o funcionamento do container antes da publicação.
- Automatize análise de vulnerabilidades e testes no pipeline.
- Publique tags imutáveis e documente o padrão adotado pela equipe.
Multi-stage builds não são apenas uma técnica para diminuir megabytes. Eles ajudam a tornar o processo de entrega mais previsível, reduzem componentes expostos e deixam claro o que a aplicação realmente precisa para rodar.
Quer tornar seus containers mais leves, seguros e prontos para escalar? Conte com a Max Alex para revisar sua arquitetura Docker, automatizar pipelines e estruturar uma operação de produção mais confiável.
Max Alex
Criador de conteúdo apaixonado por tecnologia e inovação. Acompanhe nossos artigos para ficar por dentro das melhores estratégias digitais.
Continue lendo

Como implementar templates de mensagem em campanhas transacionais: guia prático para produção
Aprenda a implementar templates de mensagem para campanhas transacionais, do mapeamento de eventos e variáveis à aprovação, integração, testes e monitoramento em produção.
Max Alex

Como implementar webhooks idempotentes em assinaturas recorrentes: guia prático para produção
Aprenda a receber, validar, deduplicar e processar webhooks de assinaturas recorrentes sem cobranças duplicadas, estados inconsistentes ou falhas difíceis de auditar.
Max Alex

Como implementar isolamento por tenant em banco compartilhado: guia prático para produção
Aprenda a implementar isolamento por tenant em banco compartilhado com tenant_id, Row Level Security, controles na aplicação, testes de acesso cruzado e práticas de produção.
Max Alex