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-bucketConfiguració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.jslambda.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_ONLYGoogle 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: LoadBalancerDespliegue 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.jsapp.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.