📚 Módulo 09: DevOps - Docker, Testes Unitários e CI/CD
Na fase final da nossa jornada corporativa, precisaremos empacotar essa infraestrutura colossal (API NestJS e Frontend Node/Next.js) para a nuvem. Entraremos na seara de automação e engenharia de confiabilidade (SRE) com Docker e GitHub Actions.
🐳 1. Docker Multi-Stage (Backend e Frontend)
O empacotamento Multi-stage é mandatório em ambientes corporativos. O Node.js possui pastas pesadas (como node_modules de desenvolvimento) que nunca devem subir para a imagem final de produção (Stage 2).
A. Dockerfile da API (NestJS Backend)
Crie na pasta raiz do repositório tecloja-backend:
# STAGE 1: Compilação e Geração do Prisma
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
COPY prisma ./prisma/
RUN npm ci
COPY . .
RUN npx prisma generate
RUN npm run build
# STAGE 2: Imagem Magra de Produção
FROM node:20-alpine
WORKDIR /app
ENV NODE_ENV=production
# Copia apenas o manifesto e instala dependências de produção
COPY package*.json ./
RUN npm ci --only=production
# Copia o Prisma e o Build compilado do Stage 1
COPY prisma ./prisma/
COPY --from=builder /app/dist ./dist
RUN npx prisma generate
EXPOSE 3000
CMD ["node", "dist/src/main.js"]
B. Dockerfile do Frontend (Next.js App Router)
Com o Next.js, não usamos Nginx. O Next.js traz seu próprio servidor otimizado. Adicione a propriedade output: 'standalone' no next.config.mjs e crie o Dockerfile abaixo na pasta raiz:
# STAGE 1: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
# A compilação do Next.js gerará a pasta otimizada .next/standalone
RUN npm run build
# STAGE 2: Produção Standalone
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
# Copia apenas a build Standalone estrita (mínima dependência possível)
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
EXPOSE 3000
# O arquivo server.js é gerado automaticamente pelo Next standalone
CMD ["node", "server.js"]
🧪 2. Testes Unitários com Jest
A integração de CI precisa de bloqueios. Se um desenvolvedor alterar a regra do Checkout e quebrar o estoque, o deploy precisa ser cancelado!
O Jest já vem acoplado ao NestJS. Rode em seu backend: npm run test
Exemplo de Teste de Validação de Domínio (src/produto/produto.service.spec.ts):
import { Test, TestingModule } from '@nestjs/testing';
import { ProdutoService } from './produto.service';
import { PrismaService } from '../prisma/prisma.service';
describe('ProdutoService', () => {
let service: ProdutoService;
let prismaMock = {
produto: { findMany: jest.fn().mockResolvedValue([{ id: 1, nome: 'Mouse', preco: 50, estoque: 10 }]) },
};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [ProdutoService, { provide: PrismaService, useValue: prismaMock }],
}).compile();
service = module.get<ProdutoService>(ProdutoService);
});
it('deve retornar a lista de produtos com sucesso do repositório', async () => {
const produtos = await service.findAll();
expect(produtos).toHaveLength(1);
expect(produtos[0].nome).toEqual('Mouse');
expect(prismaMock.produto.findMany).toHaveBeenCalledTimes(1);
});
});
🚀 3. CI/CD com GitHub Actions
Configuraremos as esteiras automatizadas que realizam o teste de qualidade e acionam o Deploy nas provedoras em nuvem ao ocorrer um push na branch main.
A. CI/CD do Backend NestJS (Deploy na Render.com)
Crie o arquivo .github/workflows/deploy.yml no projeto Backend:
name: CI/CD - NestJS Backend
on:
push:
branches: [ main ]
jobs:
qualidade:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Instalar Node.js
uses: actions/setup-node@v4
with: { node-version: 20, cache: 'npm' }
- run: npm ci
- name: Executar Testes com Jest
run: npm run test
deploy:
needs: qualidade
runs-on: ubuntu-latest
steps:
- name: Acionar Deploy Automático na Render via Webhook
run: |
curl -X POST https://api.render.com/deploy/srv-$?key=$
B. CI/CD do Frontend Next.js (Deploy na Vercel)
A Vercel é a empresa criadora do Next.js. O deploy de código Next.js lá possui performance máxima pois utiliza Edge Networking global. Ao invés do Webhook, podemos utilizar a Action oficial da Vercel para subir o front:
Crie o arquivo .github/workflows/deploy.yml no projeto Frontend:
name: CI/CD - Next.js Frontend
on:
push:
branches: [ main ]
jobs:
deploy-vercel:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Instalar Node.js
uses: actions/setup-node@v4
with: { node-version: 20, cache: 'npm' }
- run: npm ci
- run: npm run build
- name: Deploy na Vercel
uses: amondnet/vercel-action@v20
with:
vercel-token: $
vercel-org-id: $
vercel-project-id: $
vercel-args: '--prod'
✅ Pré-Requisitos deste Módulo
Antes de finalizar o curso e passar para a avaliação final, certifique-se de que:
- O faturamento de pedidos por Server Actions e o carrinho global com Zustand foram testados no frontend Next.js (Módulo 08).
- Você possui contas ativas nas plataformas de deploy (Render e Vercel) e as chaves de acesso do GitHub prontas para uso.
- Possui o executável do Docker instalado localmente (caso queira validar as imagens).
🤔 Por que fizemos assim?
- Por que ativar a diretiva
output: 'standalone'nas configurações do Next.js e criar um Dockerfile Standalone? Deploys tradicionais de Next.js exigem copiar as dependências completas donode_modules, gerando imagens pesadas (próximas a 1GB) lentas para baixar e caras para rodar. O modo standalone instrui o Next.js a analisar a árvore de dependências estritamente necessárias pelas páginas e pelas Server Actions, gerando um build auto-contido minimalista na pasta.next/standalone. Copiar apenas este diretório no estágio final do Docker reduz a imagem para cerca de 100MB, otimizando a latência de inicialização do container. - Por que rodar testes unitários mockados no Jest na esteira de CI antes de acionar o deploy? O pipeline de Integração Contínua (CI) atua como uma barreira automática de qualidade. Se um desenvolvedor alterar a regra de checkout ou de cálculo de preços de produtos de forma incorreta e commitar na branch
main, os testes do Jest falham imediatamente na máquina virtual do GitHub Actions. A esteira de deploy é abortada de forma automática, protegendo o ambiente de produção contra bugs críticos. - Por que adotar imagens de múltiplos estágios (Multi-stage Build) com a base Node Alpine no Docker? Imagens base de Linux tradicionais contêm compiladores, gerenciadores e utilitários que incham o tamanho final da imagem e aumentam a superfície de vulnerabilidade a ataques. O Multi-stage separa a fase de desenvolvimento (builder) da fase de execução (runner). A base Alpine é uma distribuição Linux focada em segurança e tamanho mínimo (menos de 10MB base), resultando em containers leves, portáveis e seguros para produção.
🔍 Checkpoint
- Sucesso no Jest: Execute
npm run testna pasta do backend NestJS e confirme se todos os testes unitários foram validados de forma limpa. - Standalone Gerado: Execute
npm run buildno frontend Next.js e certifique-se de que o compilador gerou com sucesso o diretório.next/standalone/server.js. - Pipeline Integrada: Valide se os segredos e variáveis do Render/Vercel foram preenchidos nas configurações do GitHub e verifique se as esteiras de deploy rodaram e ficaram verdes após o commit.
⚠️ Erros Comuns
| Erro | Causa | Solução |
|---|---|---|
| O container do Next.js standalone finaliza com erro alegando falta de arquivos estáticos ou públicos | O Dockerfile não copiou as pastas de assets e de estilos estáticos para o runtime final de execução. | Certifique-se de incluir as diretrizes de cópia das pastas .next/static e public no estágio final (runner) do Dockerfile do frontend conforme a especificação do guia. |
| O deploy da Vercel falha no GitHub Actions acusando falta de ID de organização ou projeto | As chaves secretas do escopo da Vercel não foram preenchidas no painel de segredos do repositório no GitHub. | Vá nas configurações do repositório no GitHub (Settings -> Secrets and variables -> Actions) e adicione os segredos VERCEL_TOKEN, VERCEL_ORG_ID e VERCEL_PROJECT_ID. |
| Vazamento de conexões de banco de dados reais nos testes locais com o Jest | O teste unitário de serviços tenta se conectar no banco físico (Postgres) em tempo de execução. | Garanta o isolamento completo da infraestrutura utilizando mocks (jest.fn().mockResolvedValue(...)) para substituir as chamadas físicas de persistência do PrismaService. |
🏆 Checklist de Sucesso Acadêmico
Seus projetos finais corporativos devem atender aos seguintes critérios absolutos:
[ ]Modelagem Relacional (1:N): Mapeado no Prisma (schema.prisma).[ ]Validation Pipes (DTO): O backend bloqueia preços negativos.[ ]Transações ACID: O$transactionestá ativo no método Checkout de Pedidos.[ ]Segurança NestJS: O Guard de Autenticação tranca rotas administrativas.[ ]Frontend BFF: O Token JWT é mascarado no servidor do Next.js em cookieHttpOnly.[ ]UX Avançado: Utilizou TailwindCSS e Zustand para o carrinho.[ ]Continuous Delivery: O CI não permite deploy com Jest quebrado!
🏁 Encerramento da Formação Full-Stack Enterprise
Missão cumprida, Arquiteto de Software! A partir de um banco de dados relacional e infraestrutura Node.js/NestJS, construímos uma casca performática de e-commerce blindada em nuvem. As habilidades adquiridas nesta maratona formam exatamente as exigências do mercado profissional internacional. Mantenha os seus servidores limpos e boa sorte nas suas próximas criações de software!