Estágio 03 · 03-02
LockedDocker é commodity, mas a maioria dos Dockerfiles em projetos reais é desastre: imagens de 2 GB com node_modules de dev, secrets em ENV, root user, build cache não usado, layers gigantes, latência fria de minutos em deploys, vulnerabilidades não tratadas. "Docker funciona" é diferente de "Docker bem usado".
Este módulo é Docker fundo: namespaces, cgroups, OverlayFS, layer caching, multi-stage builds, BuildKit, distroless, security hardening, networking, volumes, Compose pra dev, registries. Você sai construindo imagens 50-200 MB enxutas, com builds rápidos, prontas pra Kubernetes ou plataformas serverless.
Docker é wrapper sobre features Linux:
Container = processo Linux com namespaces aplicados. Não é "VM leve", VM tem kernel próprio; container compartilha kernel do host.
Image "FROM nginx:1.27" → seu Dockerfile adiciona layers. Layers comuns ficam em cache.
FROM node:22-alpine
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN corepack enable && pnpm install --frozen-lockfile
COPY . .
RUN pnpm build
EXPOSE 3000
USER node
CMD ["node", "dist/server.js"]
Cada COPY/RUN cria layer. Ordem importa pra cache: itens que mudam menos antes (deps), código depois.
Reduz imagem final separando build e runtime:
FROM node:22-alpine AS deps
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN corepack enable && pnpm install --frozen-lockfile
FROM node:22-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN pnpm build
FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package.json ./
USER node
EXPOSE 3000
CMD ["node", "dist/server.js"]
Final image só tem o necessário pra rodar. Build artifacts intermediários ficam em stages descartados.
Para Node.js mais leve: pnpm install --prod --frozen-lockfile na stage final, copiando só prod deps.
Para Next.js: output: 'standalone' em next.config.js produz .next/standalone/ com server completo + node_modules mínimas. Imagem final fica ~150 MB em vez de 1 GB.
Recomendação 2026: node:22-bookworm-slim ou gcr.io/distroless/nodejs22 na stage final.
DOCKER_BUILDKIT=1 (default em Docker 23+) habilita BuildKit:
--mount=type=cache,target=/root/.npm).--mount=type=secret,id=npm_token), não fica em layer.RUN --mount=type=ssh pra git private.Exemplo cache mount pra pnpm:
RUN --mount=type=cache,target=/pnpm/store pnpm install --frozen-lockfile
Próximo build reusa store mesmo se Dockerfile mudou.
Crucial. Sem ele, COPY . . envia node_modules, .git, build outputs pra contexto de build. Build lento e imagem inflada.
node_modules
.git
.env*
dist
.next
.cache
**/*.log
Regras:
RUN que combinam install + cleanup numa única linha (evita layer com cache lixo).ARG GIT_SHA) tarde pra não invalidar layers anteriores.COPY específico (COPY src ./src) em vez de COPY . . quando só precisa subset.Docker cria bridge docker0 por default. Container ganha veth pair, IP no range, NAT pra fora.
Drivers:
bridge (default).host (sem isolamento de rede).overlay (multi-host, Swarm/Kubernetes).macvlan (container com MAC próprio).none.Em Compose, networks default isolam por projeto. Containers no mesmo network resolvem por nome (postgres, redis).
3 tipos:
docker volume create pgdata. Persiste entre containers.-v /host/path:/container/path. Bom pra dev (live reload).Em prod: named volumes pra estado durável. Em dev: bind mounts pra código.
Cuidado: bind mount em Mac/Windows é lento (file system sync). Mac VM-based usa virtiofs/9p, performance varia.
YAML descreve serviços, networks, volumes:
services:
api:
build: .
ports: ["3000:3000"]
environment:
DATABASE_URL: postgres://app:secret@postgres:5432/app
depends_on:
postgres:
condition: service_healthy
postgres:
image: postgres:16
environment:
POSTGRES_PASSWORD: secret
volumes: [pgdata:/var/lib/postgresql/data]
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
volumes: { pgdata: }
Compose v2 (plugin) substituiu v1 (docker-compose Python). Comando: docker compose up.
depends_on apenas ordena start; não espera readiness sem condition: service_healthy.
Healthchecks importam: definem se container está "ok" pra outros dependerem.
USER node ou UID/GID explícito. Default Docker é root, péssimo.--read-only, com tmpfs pros writable paths necessários.--cap-drop=ALL --cap-add=NET_BIND_SERVICE.--security-opt=no-new-privileges.ENV API_KEY=... no Dockerfile = secret na image. Use BuildKit secrets ou runtime env.docker scout, trivy, grype. CI gate.cosign (Sigstore) pra supply chain.npm prune --production ou pnpm install --prod.apt clean && rm -rf /var/lib/apt/lists/*).node:22-alpine vs slim por compat.Meta: backend Node típico ≤ 200 MB. Front Next standalone ≤ 200 MB. Pro código novo é alcançável.
Tags:
latest em prod (mutable).@sha256:...).v1.2.3).git-sha (commit) pra rastreabilidade.Diferenças aceitáveis:
Mas: runtime base e config devem espelhar prod. Bug que aparece só em prod por divergência é cara.
Padrão: Dockerfile com stages dev e prod, ou Dockerfile + Dockerfile.dev. Compose escolhe stage via target:.
SIGTERM. Container espera stopGracePeriod (default 10s) antes de SIGKILL.tini ou dumb-init como PID 1 quando o app não reapa zombies (Node como PID 1 funciona, mas em alguns runners é safer).PID 1 reapa zumbis e propaga sinais corretamente. Linux trata PID 1 com regras especiais (defaults a ignorar SIGTERM se não há handler).
Node 12+ trata SIGTERM/SIGINT corretamente como PID 1. Mas se você fork child processes, zumbis podem acumular. tini resolve.
Em Distroless, tini já vem.
Compose: dev local, ambientes simples, prototipagem.
Kubernetes: prod escalável, multi-host, scheduler, service discovery, secrets, autoscaling. Vimos em 03-03.
Para projetos pequenos-médios em Railway/Render/Fly: Compose-like config é o que esses providers expõem por baixo.
.devcontainer/devcontainer.json define imagem + features. Reproduzível.Você precisa, sem consultar:
tini.latest vs SHA-pinning.Containerizar Logística v1 (apprentice) com produção em mente.
node:22-bookworm-slim.output: 'standalone'.api espera saudável.pgdata e redisdata..env.example documentando vars.docker-compose.test.yml) com profile separado.target: builder em vez de runner.USER non-root em todas imagens.--read-only no runtime quando viável (com tmpfs em /tmp).cap_drop: [ALL].security_opt: [no-new-privileges:true].trivy image ou docker scout cves em ambas imagens..dockerignore completo.SIGTERM corretamente. docker stop graceful.FROM node:22 (sem tag específica de OS).RUN apt-get install sem cleanup na mesma layer.COPY . . sem .dockerignore.latest tag em produção.docker images).kubectl debug ou ephemeral container).docker buildx cross-platform (linux/amd64 + linux/arm64).Destrava
03-02 é prereq dos seguintes módulos: