Documentación
Despliegue en Cloud

Despliegue en Cloud

Fox Framework está diseñado para ser desplegado fácilmente en múltiples plataformas cloud. Esta guía cubre las mejores prácticas y configuraciones específicas para diferentes proveedores de cloud.

Plataformas Soportadas

  • AWS - Amazon Web Services
  • Azure - Microsoft Azure
  • Google Cloud Platform - GCP
  • Vercel - Para aplicaciones web y APIs
  • Heroku - Plataforma como servicio
  • DigitalOcean - Droplets y App Platform
  • Railway - Plataforma moderna de despliegue

Preparación para Despliegue

Variables de Entorno

Crea un archivo .env.production con las configuraciones necesarias:

# Configuración del servidor
NODE_ENV=production
PORT=3000
HOST=0.0.0.0

# Base de datos
DATABASE_URL=postgresql://user:password@host:port/database
DATABASE_SSL=true

# Cache
REDIS_URL=redis://user:password@host:port

# Seguridad
JWT_SECRET=your-super-secret-jwt-key
SESSION_SECRET=your-session-secret
CORS_ORIGIN=https://yourdomain.com

# Servicios externos
EMAIL_SERVICE_API_KEY=your-email-api-key
STORAGE_BUCKET=your-storage-bucket

Configuración de Producción

src/config/production.ts

import { FoxConfig } from '@foxframework/core';
 
export const productionConfig: FoxConfig = {
  server: {
    port: process.env.PORT || 3000,
    host: process.env.HOST || '0.0.0.0',
    trustProxy: true
  },
  
  database: {
    url: process.env.DATABASE_URL,
    ssl: process.env.DATABASE_SSL === 'true',
    pool: {
      min: 2,
      max: 10
    },
    logging: false
  },
  
  cache: {
    url: process.env.REDIS_URL,
    ttl: 3600,
    maxMemory: '256mb'
  },
  
  security: {
    cors: {
      origin: process.env.CORS_ORIGIN?.split(',') || false,
      credentials: true
    },
    helmet: {
      contentSecurityPolicy: {
        directives: {
          defaultSrc: ["'self'"],
          styleSrc: ["'self'", "'unsafe-inline'"],
          scriptSrc: ["'self'"],
          imgSrc: ["'self'", "data:", "https:"]
        }
      }
    }
  },
  
  logging: {
    level: 'info',
    format: 'json',
    transports: ['console', 'file']
  }
};

Despliegue en AWS

AWS Lambda + API Gateway

serverless.yml

service: fox-framework-app
 
provider:
  name: aws
  runtime: nodejs18.x
  region: us-east-1
  environment:
    NODE_ENV: production
    DATABASE_URL: ${env:DATABASE_URL}
    JWT_SECRET: ${env:JWT_SECRET}
 
functions:
  api:
    handler: dist/lambda.handler
    events:
      - http:
          path: /{proxy+}
          method: ANY
          cors: true
    timeout: 30
    memorySize: 512
 
plugins:
  - serverless-webpack
  - serverless-offline
 
custom:
  webpack:
    webpackConfig: webpack.config.js

lambda.ts

import serverless from 'serverless-http';
import { createFoxApp } from './src/app';
 
const app = createFoxApp();
export const handler = serverless(app);

AWS ECS (Fargate)

Dockerfile

FROM node:18-alpine
 
WORKDIR /app
 
# Copiar archivos de dependencias
COPY package*.json ./
RUN npm ci --only=production
 
# Copiar código fuente
COPY dist/ ./dist/
COPY public/ ./public/
 
# Crear usuario no-root
RUN addgroup -g 1001 -S nodejs
RUN adduser -S foxapp -u 1001
USER foxapp
 
EXPOSE 3000
 
CMD ["node", "dist/src/server/index.js"]

task-definition.json

{
  "family": "fox-framework-app",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "256",
  "memory": "512",
  "executionRoleArn": "arn:aws:iam::account:role/ecsTaskExecutionRole",
  "containerDefinitions": [
    {
      "name": "fox-app",
      "image": "your-registry/fox-framework-app:latest",
      "portMappings": [
        {
          "containerPort": 3000,
          "protocol": "tcp"
        }
      ],
      "environment": [
        {
          "name": "NODE_ENV",
          "value": "production"
        }
      ],
      "secrets": [
        {
          "name": "DATABASE_URL",
          "valueFrom": "arn:aws:secretsmanager:region:account:secret:database-url"
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/fox-framework-app",
          "awslogs-region": "us-east-1",
          "awslogs-stream-prefix": "ecs"
        }
      }
    }
  ]
}

Despliegue en Azure

Azure Container Instances

azure-deploy.yml (GitHub Actions)

name: Deploy to Azure
 
on:
  push:
    branches: [main]
 
jobs:
  deploy:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Setup Node.js
      uses: actions/setup-node@v3
      with:
        node-version: '18'
        cache: 'npm'
    
    - name: Install dependencies
      run: npm ci
    
    - name: Build application
      run: npm run build
    
    - name: Login to Azure
      uses: azure/login@v1
      with:
        creds: ${{ secrets.AZURE_CREDENTIALS }}
    
    - name: Build and push Docker image
      run: |
        az acr build --registry ${{ secrets.ACR_NAME }} \
          --image fox-framework-app:${{ github.sha }} .
    
    - name: Deploy to Container Instances
      run: |
        az container create \
          --resource-group ${{ secrets.RESOURCE_GROUP }} \
          --name fox-framework-app \
          --image ${{ secrets.ACR_NAME }}.azurecr.io/fox-framework-app:${{ github.sha }} \
          --ports 3000 \
          --environment-variables NODE_ENV=production \
          --secure-environment-variables DATABASE_URL=${{ secrets.DATABASE_URL }}

Azure App Service

azure-pipelines.yml

trigger:
- main
 
variables:
  azureSubscription: 'Azure-Service-Connection'
  webAppName: 'fox-framework-app'
  resourceGroupName: 'fox-framework-rg'
 
stages:
- stage: Build
  jobs:
  - job: Build
    pool:
      vmImage: 'ubuntu-latest'
    
    steps:
    - task: NodeTool@0
      inputs:
        versionSpec: '18.x'
    
    - script: |
        npm ci
        npm run build
        npm run test
      displayName: 'Install, build and test'
    
    - task: ArchiveFiles@2
      inputs:
        rootFolderOrFile: '$(System.DefaultWorkingDirectory)'
        includeRootFolder: false
        archiveFile: '$(Build.ArtifactStagingDirectory)/app.zip'
    
    - task: PublishBuildArtifacts@1
      inputs:
        pathToPublish: '$(Build.ArtifactStagingDirectory)/app.zip'
        artifactName: 'drop'
 
- stage: Deploy
  dependsOn: Build
  jobs:
  - deployment: Deploy
    environment: 'production'
    pool:
      vmImage: 'ubuntu-latest'
    strategy:
      runOnce:
        deploy:
          steps:
          - task: AzureWebApp@1
            inputs:
              azureSubscription: '$(azureSubscription)'
              appType: 'webAppLinux'
              appName: '$(webAppName)'
              package: '$(Pipeline.Workspace)/drop/app.zip'
              runtimeStack: 'NODE|18-lts'

Despliegue en Google Cloud Platform

Cloud Run

cloudbuild.yaml

steps:
  # Build the container image
  - name: 'gcr.io/cloud-builders/docker'
    args: ['build', '-t', 'gcr.io/$PROJECT_ID/fox-framework-app:$COMMIT_SHA', '.']
  
  # Push the container image to Container Registry
  - name: 'gcr.io/cloud-builders/docker'
    args: ['push', 'gcr.io/$PROJECT_ID/fox-framework-app:$COMMIT_SHA']
  
  # Deploy to Cloud Run
  - name: 'gcr.io/cloud-builders/gcloud'
    args:
    - 'run'
    - 'deploy'
    - 'fox-framework-app'
    - '--image'
    - 'gcr.io/$PROJECT_ID/fox-framework-app:$COMMIT_SHA'
    - '--region'
    - 'us-central1'
    - '--platform'
    - 'managed'
    - '--allow-unauthenticated'
    - '--port'
    - '3000'
    - '--memory'
    - '512Mi'
    - '--cpu'
    - '1'
    - '--max-instances'
    - '100'
    - '--set-env-vars'
    - 'NODE_ENV=production'
 
options:
  logging: CLOUD_LOGGING_ONLY

Google Kubernetes Engine (GKE)

k8s/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: fox-framework-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: fox-framework-app
  template:
    metadata:
      labels:
        app: fox-framework-app
    spec:
      containers:
      - name: fox-app
        image: gcr.io/project-id/fox-framework-app:latest
        ports:
        - containerPort: 3000
        env:
        - name: NODE_ENV
          value: "production"
        - name: DATABASE_URL
          valueFrom:
            secretKeyRef:
              name: app-secrets
              key: database-url
        resources:
          requests:
            cpu: 100m
            memory: 256Mi
          limits:
            cpu: 500m
            memory: 512Mi
        livenessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 3000
          initialDelaySeconds: 5
          periodSeconds: 5
 
---
apiVersion: v1
kind: Service
metadata:
  name: fox-framework-app-service
spec:
  selector:
    app: fox-framework-app
  ports:
  - port: 80
    targetPort: 3000
  type: LoadBalancer

Despliegue en Vercel

Configuración para Vercel

vercel.json

{
  "version": 2,
  "builds": [
    {
      "src": "src/server/index.ts",
      "use": "@vercel/node"
    }
  ],
  "routes": [
    {
      "src": "/(.*)",
      "dest": "src/server/index.ts"
    }
  ],
  "env": {
    "NODE_ENV": "production"
  },
  "functions": {
    "src/server/index.ts": {
      "maxDuration": 30
    }
  }
}

api/index.ts (para Vercel)

import { createFoxApp } from '../src/app';
 
const app = createFoxApp();
 
export default app;

Despliegue en Heroku

Configuración para Heroku

Procfile

web: node dist/src/server/index.js
worker: node dist/src/workers/index.js

app.json

{
  "name": "Fox Framework App",
  "description": "A Fox Framework application",
  "image": "heroku/nodejs",
  "addons": [
    "heroku-postgresql:hobby-dev",
    "heroku-redis:hobby-dev"
  ],
  "env": {
    "NODE_ENV": {
      "value": "production"
    },
    "JWT_SECRET": {
      "generator": "secret"
    }
  },
  "scripts": {
    "postdeploy": "npm run db:migrate"
  }
}

Monitoreo y Observabilidad

Health Checks

import { HealthCheckController } from '@foxframework/health';
 
export class AppHealthController extends HealthCheckController {
  async checkHealth(): Promise<HealthStatus> {
    const checks = await Promise.allSettled([
      this.checkDatabase(),
      this.checkCache(),
      this.checkExternalServices()
    ]);
 
    return {
      status: checks.every(check => check.status === 'fulfilled') ? 'healthy' : 'unhealthy',
      timestamp: new Date().toISOString(),
      checks: {
        database: await this.checkDatabase(),
        cache: await this.checkCache(),
        external: await this.checkExternalServices()
      }
    };
  }
}

Métricas y Logging

import { MetricsCollector, Logger } from '@foxframework/monitoring';
 
export class ProductionMetrics {
  private metrics = new MetricsCollector();
  private logger = new Logger('production');
 
  constructor() {
    this.setupMetrics();
  }
 
  private setupMetrics() {
    // Métricas de aplicación
    this.metrics.counter('http_requests_total', 'Total HTTP requests');
    this.metrics.histogram('http_request_duration_ms', 'HTTP request duration');
    this.metrics.gauge('active_connections', 'Active connections');
 
    // Métricas de negocio
    this.metrics.counter('users_created_total', 'Total users created');
    this.metrics.counter('orders_processed_total', 'Total orders processed');
  }
 
  // Endpoint para Prometheus
  async getMetrics(): Promise<string> {
    return this.metrics.export();
  }
}

Configuración de CDN

CloudFlare

// Worker script para CloudFlare
addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request));
});
 
async function handleRequest(request) {
  const cache = caches.default;
  const cacheKey = new Request(request.url, request);
  
  // Verificar caché
  let response = await cache.match(cacheKey);
  
  if (!response) {
    // Fetch from origin
    response = await fetch(request);
    
    // Cache static assets
    if (request.url.includes('/static/')) {
      const cacheResponse = response.clone();
      cacheResponse.headers.set('Cache-Control', 'public, max-age=86400');
      event.waitUntil(cache.put(cacheKey, cacheResponse));
    }
  }
  
  return response;
}

Scripts de Automatización

Script de Despliegue

scripts/deploy.sh

#!/bin/bash
 
set -e
 
echo "🚀 Iniciando despliegue..."
 
# Verificar branch
if [ "$(git branch --show-current)" != "main" ]; then
  echo "❌ Solo se puede desplegar desde la rama main"
  exit 1
fi
 
# Verificar que no hay cambios sin commit
if [ -n "$(git status --porcelain)" ]; then
  echo "❌ Hay cambios sin commit"
  exit 1
fi
 
# Ejecutar tests
echo "🧪 Ejecutando tests..."
npm test
 
# Build
echo "🔨 Construyendo aplicación..."
npm run build
 
# Deploy según plataforma
case $1 in
  "aws")
    echo "☁️ Desplegando en AWS..."
    npm run deploy:aws
    ;;
  "azure")
    echo "☁️ Desplegando en Azure..."
    npm run deploy:azure
    ;;
  "gcp")
    echo "☁️ Desplegando en GCP..."
    npm run deploy:gcp
    ;;
  "vercel")
    echo "▲ Desplegando en Vercel..."
    vercel --prod
    ;;
  *)
    echo "❌ Plataforma no soportada: $1"
    echo "Plataformas disponibles: aws, azure, gcp, vercel"
    exit 1
    ;;
esac
 
echo "✅ Despliegue completado!"

Mejores Prácticas

1. Seguridad

  • Usa variables de entorno para secretos
  • Implementa HTTPS/TLS en todos los entornos
  • Configura firewalls y reglas de seguridad
  • Utiliza secrets managers para credenciales

2. Escalabilidad

  • Configura auto-scaling
  • Usa load balancers
  • Implementa health checks
  • Monitorea recursos y performance

3. Disponibilidad

  • Despliega en múltiples zonas
  • Implementa estrategias de backup
  • Configura alertas de monitoreo
  • Usa blue-green deployments

4. Costos

  • Monitorea uso de recursos
  • Usa instancias apropiadas para la carga
  • Implementa auto-shutdown para entornos de desarrollo
  • Optimiza imágenes Docker

5. DevOps

  • Automatiza despliegues con CI/CD
  • Usa Infrastructure as Code
  • Implementa rollback automático
  • Mantén logs centralizados

Fox Framework está diseñado para funcionar óptimamente en cualquier plataforma cloud, proporcionando la flexibilidad y escalabilidad que tu aplicación necesita.