404 Not Found

404 Not Found


nginx

Project Deployment

Agora que o MegaShop foi desenvolvido, Charlie precisa implantá-lo no ambiente de produção. Isso não é apenas um simples npm run build—requer orquestração Docker para todo o conjunto de serviços, um pipeline de automação CI/CD, monitoramento de runtime e rastreamento de erros, e uma lista de verificação de implantação abrangente. Implante uma vez, rode de forma estável a longo prazo.

1. O Que Você Vai Aprender


2. Uma História Real de um Arquiteto

(1) Dor: Crash Imediato ao Lançar

A primeira implantação do MegaShop por Charlie—ele esqueceu de executar as migrações do banco de dados, não configurou as variáveis de ambiente, não iniciou o Redis, e o certificado SSL havia expirado. Cinco minutos após ir ao ar, Alice notou um erro 500, e levou uma hora para Bob reverter as alterações manualmente.

(2) Soluções para Sistemas de Implantação de Nível de Produção

Um sistema de implantação abrangente: CI/CD automatizado + Docker Compose + monitoramento + lista de verificação de implantação, com validação em cada etapa e rollback automático em caso de erros.

(3) Benefícios: Automação + Observabilidade

Uma vez que o código é feito push, ele é implantado automaticamente; Sentry captura erros em tempo real; Prometheus monitora métricas de performance; e Alice nunca mais encontrará um erro 500 não detectado.


3. Otimização de Build de Produção

(1) Análise dos Produtos de Construção

(1) ▶ Exemplo: Análise e Otimização de Build

BASH
# Build para produção
npm run build

# Analisar bundle
npx nuxi analyze

Saída:

TEXT
# Comando executado com sucesso

(2) ▶ Exemplo: Verificação de Segurança de Variáveis de Ambiente

TYPESCRIPT
// server/utils/env-check.ts
export default defineEventHandler((event) => {
  if (getRequestURL(event).pathname !== '/api/health') return

  const config = useRuntimeConfig()
  const required = ['databaseUrl', 'jwtAccessSecret', 'jwtRefreshSecret']
  const missing = required.filter(key => !config[key as keyof typeof config])

  if (missing.length > 0 && process.env.NODE_ENV === 'production') {
    console.error(`Missing required env vars: ${missing.join(', ')}`)
  }

  return {
    status: missing.length === 0 ? 'ok' : 'degraded',
    timestamp: Date.now(),
    version: process.env.APP_VERSION || 'unknown'
  }
})

Saída:

TEXT
// Execução bem-sucedida

(2) Checklist de Otimização de Desenvolvimento

Item de Verificação Requisito Método de Verificação
JS Bundle gzip < 200KB nuxi analyze
Extração de CSS ✅ Arquivo Separado Verificação do Output de Build
Imagens WebP ✅ Conversão Automática Validação NuxtImg
Variáveis de Ambiente Sem Chaves Hard-Coded Verificação grep
Tree Shaking Sem Código Não Utilizado Análise de Bundle
Source Map Desabilitado em Produção nuxt.config.ts

4. Orquestração Docker Compose

(1) Fluxo de Implantação de Produção

100%
flowchart TB
    A[Git Push] --> B[GitHub Actions CI]
    B --> C{Testes Passaram?}
    C -->|Não| D[Notificar Equipe + Bloquear]
    C -->|Sim| E[Buildar Imagem Docker]
    E --> F[Push para Registry]
    F --> G[Implantar em Staging]
    G --> H{Smoke Test?}
    H -->|Não| I[Rollback Staging]
    H -->|Sim| J[Implantar em Produção]
    J --> K{Health Check?}
    K -->|Não| L[Rollback Automático]
    K -->|Sim| M[Concluído ✅]

(1) ▶ Exemplo: Docker Compose de Nível de Produção

YAML
# docker-compose.prod.yml
version: '3.8'

services:
  web:
    image: ghcr.io/megashop/megashop:latest
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgresql://megashop:${DB_PASSWORD}@db:5432/megashop
      - REDIS_URL=redis://redis:6379
      - JWT_ACCESS_SECRET=${JWT_ACCESS_SECRET}
      - JWT_REFRESH_SECRET=${JWT_REFRESH_SECRET}
      - DEPLOY_TARGET=node-server
    depends_on:
      db: { condition: service_healthy }
      redis: { condition: service_started }
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
      interval: 30s
      timeout: 10s
      retries: 3
    restart: unless-stopped
    deploy:
      resources:
        limits: { memory: 1G, cpus: '1.0' }

  db:
    image: postgres:16-alpine
    environment:
      - POSTGRES_USER=megashop
      - POSTGRES_PASSWORD=${DB_PASSWORD}
      - POSTGRES_DB=megashop
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U megashop"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    command: redis-server --requirepass ${REDIS_PASSWORD} --maxmemory 256mb --maxmemory-policy allkeys-lru
    volumes:
      - redis_data:/data
    restart: unless-stopped

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.prod.conf:/etc/nginx/nginx.conf:ro
      - ./ssl:/etc/nginx/ssl:ro
    depends_on:
      - web
    restart: unless-stopped

volumes:
  postgres_data:
  redis_data:

Saída:

TEXT
CONTAINER ID   IMAGE          STATUS         PORTS
abc123         nginx:latest   Up 2 hours     0.0.0.0:80->80/tcp

5. Pipeline CI/CD

(1) ▶ Exemplo: Workflow Completo de Implantação de Produção

YAML
# .github/workflows/deploy-production.yml
name: Deploy Production

on:
  release:
    types: [published]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: megashop/megashop

jobs:
  test:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:16-alpine
        env: { POSTGRES_USER: test, POSTGRES_PASSWORD: test, POSTGRES_DB: megashop_test }
        ports: ['5432:5432']
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20, cache: npm }
      - run: npm ci
      - run: npx prisma migrate deploy
        env: { DATABASE_URL: postgresql://test:test@localhost:5432/megashop_test }
      - run: npm run lint
      - run: npm run typecheck
      - run: npm run test:coverage

  build-push:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GHCR_TOKEN }}
      - uses: docker/build-push-action@v5
        with:
          push: true
          tags: |
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest

  deploy:
    needs: build-push
    runs-on: ubuntu-latest
    environment: production
    steps:
      - name: Deploy via SSH
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.PROD_HOST }}
          username: ${{ secrets.PROD_USER }}
          key: ${{ secrets.PROD_SSH_KEY }}
          script: |
            cd /opt/megashop
            docker pull ghcr.io/megashop/megashop:latest
            docker compose -f docker-compose.prod.yml up -d --no-build
            docker compose exec web npx prisma migrate deploy
            echo "Deploy completed at $(date)"

      - name: Health check
        run: |
          for i in {1..15}; do
            if curl -sf https://megashop.com/api/health; then
              echo "Health check passed"
              exit 0
            fi
            echo "Waiting for health check... ($i/15)"
            sleep 5
          done
          echo "Health check failed!"
          exit 1

      - name: Rollback on failure
        if: failure()
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.PROD_HOST }}
          username: ${{ secrets.PROD_USER }}
          key: ${{ secrets.PROD_SSH_KEY }}
          script: |
            cd /opt/megashop
            docker compose down
            docker tag ghcr.io/megashop/megashop:previous ghcr.io/megashop/megashop:latest
            docker compose -f docker-compose.prod.yml up -d --no-build
            echo "Rollback completed at $(date)"

Saída:

TEXT
CONTAINER ID   IMAGE          STATUS         PORTS
abc123         nginx:latest   Up 2 hours     0.0.0.0:80->80/tcp

6. Monitoramento e Logging

(1) ▶ Exemplo: Rastreamento de Erros Sentry

TYPESCRIPT
// plugins/sentry.client.ts
import * as Sentry from '@sentry/vue'

export default defineNuxtPlugin((nuxtApp) => {
  const config = useRuntimeConfig()

  Sentry.init({
    dsn: config.public.sentryDsn,
    environment: config.public.environment,
    release: config.public.version,
    integrations: [
      new Sentry.BrowserTracing({
        routingInstrumentation: Sentry.vueRouterInstrumentation(nuxtApp.$router)
      })
    ],
    tracesSampleRate: 0.1,
    replaysSessionSampleRate: 0.1,
    replaysOnErrorSampleRate: 1.0
  })

  return {
    provide: {
      sentry: Sentry
    }
  }
})

Saída:

TEXT
// Execução bem-sucedida

(2) ▶ Exemplo: Logs do lado do servidor

TYPESCRIPT
// server/middleware/logging.ts
export default defineEventHandler((event) => {
  const start = Date.now()
  const method = getMethod(event)
  const url = getRequestURL(event)

  event.node.res.on('finish', () => {
    const duration = Date.now() - start
    const status = event.node.res.statusCode

    // Log estruturado
    const logEntry = {
      method, url: url.pathname,
      status, duration,
      userId: event.context.user?.id || null,
      timestamp: new Date().toISOString()
    }

    if (status >= 500) {
      console.error(JSON.stringify(logEntry))
    } else if (duration > 1000) {
      console.warn(JSON.stringify({ ...logEntry, alert: 'slow_request' }))
    } else {
      console.log(JSON.stringify(logEntry))
    }
  })
})

Saída:

TEXT
// Execução bem-sucedida

(3) ▶ Exemplo: API de Health Check

TYPESCRIPT
// server/api/health.get.ts
export default defineEventHandler(async () => {
  const checks: Record<string, string> = {}

  // Verificar banco de dados
  try {
    await prisma.$queryRaw`SELECT 1`
    checks.database = 'ok'
  } catch {
    checks.database = 'error'
  }

  // Verificar Redis
  try {
    const storage = useStorage('products')
    await storage.setItem('health-check', 'ok', { ttl: 10 })
    checks.redis = 'ok'
  } catch {
    checks.redis = 'error'
  }

  const allOk = Object.values(checks).every(v => v === 'ok')

  setHeader(useEvent(), 'cache-control', 'no-store')

  return {
    status: allOk ? 'ok' : 'degraded',
    checks,
    version: process.env.APP_VERSION || 'unknown',
    uptime: process.uptime(),
    timestamp: new Date().toISOString()
  }
})

Saída:

TEXT
// Execução bem-sucedida

7. Lista de Verificação de Implantação

(1) Inspeção de Lançamento em Produção

# Item de Verificação Ação Método de Verificação
1 Certificado SSL Configurar Let's Encrypt curl -v https://megashop.com
2 Variáveis de Ambiente Todas as chaves foram configuradas verificação /api/health
3 Migração de Banco de Dados prisma migrate deploy Validação de Consulta de Produto
4 Conexão Redis Iniciar e Conectar Verificar /api/health
5 Configuração CDN Cloudflare/CloudFront Cache Hits de Recursos Estáticos
6 Aquecimento de Cache Primeira Visita a Páginas Populares de Produto curl Home Page + Página de Lista
7 Health Check /api/health retorna "ok" Verificação Automatizada
8 Inicialização Sentry Rastreamento de Erros Habilitado Acionar Erro de Teste
9 Geração de Sitemap /sitemap.xml está acessível Google Search Console
10 Plano de Rollback Imagem Antiga Disponível Documentar Passos de Rollback

(2) Plano de Rollback

Passo Ação Comando
1 Parar o serviço atual docker compose down
2 Restaurar Imagem Antiga docker tag xxx:previous xxx:latest
3 Iniciar versão anterior docker compose up -d --no-build
4 Health Check curl /api/health
5 Notificar a Equipe Notificações Slack/Email

8. Exemplo Completo: Comandos de Implantação do MegaShop

BASH
# ============================================
# Implantação de Produção do MegaShop
# Implantação completa + configuração de monitoramento
# ============================================

# 1. Configurar servidor (apenas na primeira vez)
ssh prod-server
mkdir -p /opt/megashop/ssl
# Copiar certificados SSL
# Copiar .env com segredos de produção

# 2. Implantação inicial
cd /opt/megashop
git clone https://github.com/megashop/megashop.git .
docker compose -f docker-compose.prod.yml up -d

# 3. Configuração do banco de dados
docker compose exec web npx prisma migrate deploy
docker compose exec web npx prisma db seed

# 4. Verificar
curl -f https://megashop.com/api/health
curl -f https://megashop.com/sitemap.xml

# 5. Aquecimento de cache
curl https://megashop.com/
curl https://megashop.com/products
curl https://megashop.com/products/1

# 6. Monitorar
docker compose logs -f web
# Verificar dashboard do Sentry
# Verificar endpoint de health periodicamente

❓ Perguntas Frequentes

P Como atualizar uma imagem Docker?
R CI/CD constrói e faz push automaticamente de novas imagens para GHCR; no servidor, execute docker pull seguido de docker-compose up -d --no-build. Use blue-green deployment para zero downtime.
P A cota gratuita do Sentry é suficiente?
R O plano gratuito inclui 5.000 eventos de erro por mês. Isso é suficiente para o MegaShop nos estágios iniciais; você pode atualizar conforme necessário mais tarde. Erros de desenvolvimento não são contados (apenas erros de produção são reportados).
P O endpoint de health check requer autenticação?
R Não. /api/health deve ser publicamente acessível para uso por load balancers, K8s e health checks do Docker. No entanto, não exponha nenhuma informação sensível.
P Como aquecer o cache?
R Após a implantação, use um script para acessar páginas populares (homepage, páginas de lista, Top 100 detalhes de produto) para acionar a geração de cache ISR. Isso também pode ser automatizado após o seeding.
P Como os logs são coletados?
R Para logs Docker, use docker compose logs. Para ambientes de produção, recomendamos ELK (Elasticsearch + Logstash + Kibana) ou Loki + Grafana. Nos estágios iniciais, o MegaShop usou entradas console.log estruturadas combinadas com Sentry.
P O que devo fazer se uma migração de banco de dados falhar?
R prisma migrate deploy apenas aplica arquivos de migração validados. Se uma migração falhar, corrija o arquivo de migração e redeploy. Nunca use prisma migrate reset em produção (resultará em perda de dados).

📖 Resumo


📝 Exercícios

  1. Exercício Básico (Dificuldade: ⭐): Implante o MegaShop em um ambiente de produção (Docker Compose) e verifique que /api/health retorna "ok"
  2. Exercício Avançado (Dificuldade: ⭐⭐): Configure GitHub Actions CI/CD para implantar automaticamente ao fazer push no branch main, incluindo health checks e rollbacks automáticos
  3. Desafio (Dificuldade: ⭐⭐⭐): Construa um sistema de operações completo—rastreamento de erros Sentry + logging estruturado + métricas Prometheus + validação automatizada de checklists de implantação

---|

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%