ADR-003: Multi-Stage Docker Builds com Turbo Prune e BuildKit Caching
Context
O monorepo contém múltiplos microsserviços Node.js (por exemplo, servidores de API, serviços MCP, frontends web) gerenciados via workspaces do PNPM e Turborepo. Anteriormente, a construção concorrente dessas imagens Docker via Skaffold gerava ineficiências:
- Copiar todo o package.json raiz e os workspaces acionava invalidações de cache em todos os serviços sempre que um pacote não relacionado sofria alterações.
- Comandos pnpm install independentes dentro de cada contexto de build do Docker desperdiçavam largura de banda e duplicavam entradas de cache para dependências idênticas.
Decision
Padronizaremos todos os Dockerfiles Node.js no monorepo para utilizar uma arquitetura multi-stage que aproveita a limpeza (pruning) do Turborepo e os montagens de cache do Docker BuildKit:
- Turborepo Prune (
turbo prune --docker): Um estágio de pruner inicial cria um snapshot mínimo e isolado do workspace específico e de suas dependências internas (out/json e out/full). - Shared BuildKit Cache Mount (
id=pnpm-store-shared): Os estágiosbuildere deployer utilizam--mount=type=cache,id=pnpm-store-shared,target=/pnpm/store. Isso permite que builds concorrentes do Skaffold compartilhem o mesmo repositório virtual do PNPM no daemon do host, garantindo que os pacotes sejam baixados exatamente uma vez. - Deployer Isolation (
pnpm deploy): Os builds de produção utilizampnpm --filter \<workspace\> --prod deploypara extrair um ambiente de produção autossuficiente, livre de dependências de desenvolvimento ou artefatos de código-fonte.
Consequences
- Os tempos de build são significativamente reduzidos através de uma taxa de acerto de cache de camadas de 90% e downloads de rede sem duplicação.
- As imagens Docker são incrivelmente leves, contendo apenas ativos compilados e dependências de produção.
- Alterações em um workspace não invalidam o cache de build do Docker de workspaces não relacionados.