Docker: reduzindo imagem de 1GB para 50MB na prática
Tabela de Conteúdo
Imagem Docker de 1GB? Deploy demorando 10 minutos? Vamos resolver isso.
O primeiro passo é entender exatamente o que está deixando sua imagem gigante. Antes de otimizar, precisamos diagnosticar o problema:
Diagnóstico rápido
# Ver tamanho das imagens
$ docker images --format "table {{.Repository}}\t{{.Size}}\t{{.Tag}}"
# Ver layers da imagem
$ docker history <imagem>:tag
Problemas comuns que deixam imagem gigante
1) Usar imagem base Ubuntu/Debian
# NÃO FAÇA ISSO
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y nodejs npm
Resultado: ~800MB só do base
2) Copiar tudo antes de instalar dependências
# NÃO FAÇA ISSO
COPY . .
RUN npm install
Resultado: Cache invalidado toda vez
3) Não usar .dockerignore
Resultado: node_modules, .git, logs vão para imagem
Soluções práticas
Vamos resolver esses problemas com técnicas que funcionam na prática:
Solução 1: Multistage build
Antes (1.2GB)
FROM node:18
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]
Depois (45MB)
# Stage 1: Build
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
# Stage 2: Runtime
FROM node:18-alpine AS runtime
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package.json ./package.json
# Remove usuário não essencial
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
USER nextjs
EXPOSE 3000
CMD ["npm", "start"]
Solução 2: .dockerignore
.dockerignore
# .dockerignore
node_modules
npm-debug.log
.git
.gitignore
README.md
.env
.nyc_output
coverage
.nyc_output
.coverage
.cache
dist
Solução 3: Alpine vs Distroless
Alpine (45MB)
FROM node:18-alpine
RUN apk add --no-cache dumb-init
Distroless (25MB)
FROM node:18 AS builder
# ... build stage
FROM gcr.io/distroless/nodejs18
COPY --from=builder /app/dist ./dist
Comandos úteis do dia a dia
# Build com cache otimizado
$ docker build --build-arg BUILDKIT_INLINE_CACHE=1 --cache-from <imagem>:latest -t <imagem>:latest .
# Ver tamanho de cada layer
$ docker history --human --format "table {{.CreatedBy}}\t{{.Size}}" <imagem>:tag
# Limpar cache do Docker
$ docker builder prune -f
# Analisar imagem com dive
$ dive <imagem>:tag
# Ver vulnerabilidades
$ docker scan <imagem>:tag
Resultado esperado
Com as técnicas deste post, você pode reduzir uma imagem Node.js:
- Imagem base ubuntu: ~800MB → Alpine: ~50MB
- Sem .dockerignore: +200-500MB → Com .dockerignore: economia de 200-500MB
- Single stage: build tools incluídos → Multistage: só runtime
Resultado típico: 1GB+ → 30-60MB (redução de 90-95%)
Dica final
Comece pelo .dockerignore. Muitas vezes só isso já reduz 200-300MB.
Depois use multistage. Só isso já resolve 90% dos casos.
Simples assim! :)