Node.js em Docker pode ser lento e pesado. Técnicas específicas reduzem imagem de 1GB para 100MB e aceleram builds em 5x.
Conceitos Principais
Layer Caching Node
COPY package*.json antes de COPY código. npm install cacheia se package.json não muda. Economiza minutos por build.
node_modules em Docker
NUNCA copie node_modules local. Use npm ci (lockfile strict). Multi-stage: build deps separado de runtime deps.
Alpine para Node
node:18-alpine vs node:18 = 170MB vs 1GB. Alpine suficiente para 95% dos casos. Use debian apenas se nativa deps.
npm ci vs npm install
npm ci: deleta node_modules, instala do lockfile, mais rápido. npm install: resolve deps, atualiza lockfile. CI sempre npm ci.
Passo a Passo
- Dockerfile Otimizado: FROM node:18-alpine. WORKDIR /app. COPY package*.json ./. RUN npm ci --only=production. COPY . . USER node. CMD ["node", "server.js"].
- Multi-Stage Build: Stage builder: npm ci (com devDeps), build TypeScript. Stage production: npm ci --only=production, COPY dist/ e node_modules prod.
- Cache npm: Docker: RUN --mount=type=cache,target=/root/.npm npm ci. BuildKit cache mount. Build subsequente usa cache npm.
- Dev com Hot Reload: Bind mount código: -v $(pwd):/app. node_modules em volume anônimo: -v /app/node_modules. Nodemon detecta mudanças.
- .dockerignore: node_modules, .git, .env*, *.md, tests/, coverage/, dist/. Build context de 500MB para 5MB. 10x mais rápido.
Boas Praticas
Recomendacoes
• npm ci ao invés de npm install sempre
• package-lock.json commitado no git
• Multi-stage para apps TypeScript
• Dumb-init ou tini para PID 1 correto
• NODE_ENV=production para otimizações
• Healthcheck endpoint /health
Erros Comuns
Evite estes erros
• COPY node_modules do host
• npm install sem lockfile
• Não usar .dockerignore
• COPY . . antes de package.json
• Rodar como root (user node existe)
Checklist
- Dockerfile com layer caching otimizado
- npm ci em vez de npm install
- .dockerignore configurado
- Imagem Alpine
- Multi-stage se TypeScript
- USER node configurado
- Build < 2min
- Imagem < 200MB