Imagens inchadas do Docker retardam implantações, desperdiçam armazenamento, aumentam a superfície de ataque e custam dinheiro em largura de banda. Uma imagem Node.js ou Python não otimizada típica pode ter mais de 1 GB; com as técnicas certas, o mesmo aplicativo cabe em menos de 100 MB. Veja como reduzir drasticamente as imagens do Docker.
📋 Table of Contents
- Por que o tamanho da imagem é importante
- Técnica 1: Construções em vários estágios (maior vitória)
- Técnica 2: Use imagens de base mínimas
- Técnica 3: Otimize o cache de camadas
- Técnica 4: Use .dockerignore
- Técnica 5: Combine e limpe comandos RUN
- Exemplo de Python: Multiestágio + Slim
- Medindo e analisando o tamanho da imagem
- Lista de verificação de otimização
- Perguntas frequentes
- imagens
Por que o tamanho da imagem é importante
- Implantações mais rápidas: Imagens menores são puxadas e iniciadas mais rapidamente, especialmente durante o dimensionamento
- Custos mais baixos: Menos armazenamento de registro e largura de banda (é importante em escala)
- Superfície de ataque menor: Menos pacotes significa menos vulnerabilidades
- CI/CD mais rápido: Criar e enviar imagens menores acelera pipelines
Técnica 1: Construções em vários estágios (maior vitória)
Construa em um estágio com todas as ferramentas de construção e copie apenas o artefato final em uma imagem limpa e mínima:
# 🐛 Single-stage — includes build tools, dev deps, source (1.1GB)
FROM node:20
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
CMD ["node", "dist/index.js"]
# ✅ Multi-stage — final image has only runtime + built output (150MB)
# Build stage
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Runtime stage — clean slate
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev # production deps only
COPY --from=builder /app/dist ./dist # copy ONLY the built output
CMD ["node", "dist/index.js"]
Técnica 2: Use imagens de base mínimas
| Imagem base | Tamanho aproximado | Notas |
|---|---|---|
| nó:20 | ~1,1 GB | Debian completo — evite para produção |
| nó:20-slim | ~240 MB | Debian cortado — bom padrão |
| nó:20-alpino | ~180 MB | Alpine Linux — pequeno, comum |
| gcr.io/distroless/nodejs | ~170 MB | Sem gerenciador de shell/pacote — mais seguro |
# Alpine — smallest common choice
FROM node:20-alpine
# Distroless — no shell, no package manager, minimal attack surface
FROM gcr.io/distroless/nodejs20-debian12
COPY --from=builder /app/dist /app/dist
CMD ["/app/dist/index.js"]
Técnica 3: Otimize o cache de camadas
# 🐛 Copying everything first breaks caching — any code change
# re-runs npm install
COPY . .
RUN npm ci
# ✅ Copy dependency files first, install, THEN copy source
COPY package*.json ./
RUN npm ci # this layer is cached unless package.json changes
COPY . . # only this layer rebuilds on code changes
RUN npm run build
Ordene as instruções do Dockerfile das menos alteradas para as mais alteradas. As dependências mudam raramente, a fonte muda constantemente – portanto, instale as dependências antes de copiar a fonte para maximizar os acessos ao cache.
Técnica 4: Use .dockerignore
# .dockerignore — exclude files that bloat the build context
node_modules
npm-debug.log
.git
.gitignore
.env
.env.*
dist
coverage
.vscode
.idea
README.md
*.md
.DS_Store
tests
**/*.test.js
Sem.dockerignore, COPY . . envia todo o seu diretório (incluindo node_modules, .git) para a compilação – retardando as compilações e potencialmente vazando segredos.
Técnica 5: Combine e limpe comandos RUN
# 🐛 Each RUN creates a layer; cleanup in a separate layer doesn't shrink
RUN apt-get update
RUN apt-get install -y curl
RUN rm -rf /var/lib/apt/lists/* # too late — previous layers keep the data
# ✅ Combine into one layer with cleanup in the same RUN
RUN apt-get update && \
apt-get install -y --no-install-recommends curl && \
rm -rf /var/lib/apt/lists/* # cleanup in the SAME layer
Exemplo de Python: Multiestágio + Slim
# Build stage — compile dependencies
FROM python:3.12 AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
# Runtime stage — slim base + only installed packages
FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY . .
ENV PATH=/root/.local/bin:$PATH
CMD ["python", "app.py"]
# Result: ~150MB instead of ~1GB
Medindo e analisando o tamanho da imagem
# Check image size
docker images myapp
# Analyze layers to find what's taking space
docker history myapp:latest
# Use 'dive' for detailed layer analysis
dive myapp:latest
# Shows wasted space and what each layer adds
Lista de verificação de otimização
- Use compilações de vários estágios — copie apenas artefatos de tempo de execução para a imagem final
- Use imagens de base alpinas, finas ou distroless
- Copie os arquivos de dependência e instale antes de copiar a origem (cache da camada)
- Adicione um abrangente
.dockerignore - Instale apenas dependências de produção (
npm ci --omit=dev,pip --no-cache-dir) - Combine comandos RUN e limpe na mesma camada
- Fixe versões de imagem base para reprodutibilidade
Perguntas frequentes
Q: Alpine é sempre a melhor imagem base?
R: Geralmente menor, mas Alpine usa musl libc que ocasionalmente causa problemas com módulos nativos ou DNS. Se você tiver problemas de compatibilidade, use slim (baseado em Debian) – ainda é pequeno e mais compatível. Distroless é melhor for security.
Q: What is distroless and should I use it?
A: Distroless images contain only your app and its runtime — no shell, no package manager, minimal OS. This shrinks size and dramatically reduces attack surface. Great for production, but harder to debug (no shell to exec into).
Q: How much smaller can I realistically get?
A: Multi-stage builds plus a minimal base commonly reduce images by 70-90%. Uma imagem Node.js de 1 GB geralmente fica entre 100 e 150 MB. O Distroless pode ficar ainda menor
P: O tamanho da imagem afeta o desempenho do tempo de execução?
P: Por que minha imagem permanece grande apesar dos comandos de limpeza?
R: As camadas do Docker são imutáveis — se você adicionar arquivos em uma camada e excluí-los em outra, os dados excluídos ainda existirão na camada anterior. A otimização das imagens do Docker se resume a algumas técnicas de alto impacto:
compilações de vários estágios
imagens
(alpine, slim ou distroless),cache de camada inteligente(dependências antes da fonte) e um.dockerignoreAplique a lista de verificação aos seus arquivos Docker e meça os resultados.Aplique a lista de verificação aos seus arquivos Docker e meça os resultados.Aplique a lista de verificação aos seus arquivos Docker e meça os resultados.Aplique a lista de verificação aos seus arquivos Docker e meça os resultados.Aplique a lista de verificação aos seus arquivos Docker e meça os resultados.docker history or dive.
🔗 Share this article
✍️ Leave a Comment