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
- Otimização de Build de Produção: análise nuxt build + otimização de bundle + segurança de variáveis de ambiente
- Orquestração Docker Compose: Nuxt + PostgreSQL + Redis + Nginx
- Pipeline CI/CD: Testes Automatizados com GitHub Actions + Implantação em Múltiplos Ambientes
- Monitoramento e Logging: Rastreamento de Erros Sentry + Logging de API + Métricas de Performance
- Lista de Verificação de Implantação: SSL/CDN/Migração/Aquecimento de Cache/Plano de Rollback
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
# Build para produção
npm run build
# Analisar bundle
npx nuxi analyze
Saída:
# Comando executado com sucesso
(2) ▶ Exemplo: Verificação de Segurança de Variáveis de Ambiente
// 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:
// 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
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
# 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:
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
# .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:
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
// 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:
// Execução bem-sucedida
(2) ▶ Exemplo: Logs do lado do servidor
// 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:
// Execução bem-sucedida
(3) ▶ Exemplo: API de Health Check
// 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:
// 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
# ============================================
# 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
docker pull seguido de docker-compose up -d --no-build. Use blue-green deployment para zero downtime.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.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
- Build de produção: análise de bundle + segurança de variáveis de ambiente + Source Maps desabilitados
- Orquestração Docker Compose: Stack Completa de Serviços Nuxt + PostgreSQL + Redis + Nginx
- CI/CD: GitHub Actions—testes automatizados, build, implantação, health checks e rollbacks automáticos
- Monitoramento: Rastreamento de erros Sentry + logging estruturado + API de health check
- Checklist de implantação com 10 itens: SSL, variáveis de ambiente, migração, Redis, CDN, aquecimento de cache, plano de rollback
📝 Exercícios
- Exercício Básico (Dificuldade: ⭐): Implante o MegaShop em um ambiente de produção (Docker Compose) e verifique que /api/health retorna "ok"
- 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 - 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
---|



