Files
math2-platform/scripts/deploy.sh
Renato bc43c9e772
Some checks failed
Test Suite / test-backend (push) Has been cancelled
Test Suite / test-frontend (push) Has been cancelled
Test Suite / e2e-tests (push) Has been cancelled
Test Suite / coverage-check (push) Has been cancelled
🎓 Initial commit: Math2 Platform - Plataforma de Álgebra Lineal PRO
 Características:
- 45 ejercicios universitarios (Basic → Advanced)
- Renderizado LaTeX profesional
- IA generativa (Z.ai/DashScope)
- Docker 9 servicios
- Tests 123/123 pasando
- Seguridad enterprise (JWT, XSS, Rate limiting)

🐳 Infraestructura:
- Next.js 14 + Node.js 20
- PostgreSQL 15 + Redis 7
- Docker Compose completo
- Nginx + SSL ready

📚 Documentación:
- 5 informes técnicos completos
- README profesional
- Scripts de deployment automatizados

Estado: Producción lista 
2026-03-31 11:27:11 -03:00

360 lines
8.8 KiB
Bash
Executable File

#!/bin/bash
# ========================================
# MATH PLATFORM - PRODUCTION DEPLOYMENT
# Enterprise Grade Deployment Script
# ========================================
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
BACKUP_DIR="$PROJECT_DIR/backups"
LOG_DIR="$PROJECT_DIR/logs"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
# Logging functions
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Error handler
error_handler() {
log_error "Deployment failed at line $1"
log_info "Rolling back to previous state..."
rollback_deployment
exit 1
}
trap 'error_handler $LINENO' ERR
# ========================================
# PRE-DEPLOYMENT CHECKS
# ========================================
check_prerequisites() {
log_info "Checking prerequisites..."
# Check if running as root (should NOT)
if [[ $EUID -eq 0 ]]; then
log_error "Do not run this script as root"
exit 1
fi
# Check required commands
local required_commands=("docker" "docker-compose" "curl" "wget")
for cmd in "${required_commands[@]}"; do
if ! command -v "$cmd" &> /dev/null; then
log_error "$cmd is required but not installed"
exit 1
fi
done
# Check Docker is running
if ! docker info &> /dev/null; then
log_error "Docker daemon is not running"
exit 1
fi
log_success "Prerequisites check passed"
}
check_environment() {
log_info "Checking environment variables..."
local required_vars=(
"DATABASE_URL"
"REDIS_PASSWORD"
"JWT_SECRET"
)
local missing_vars=()
for var in "${required_vars[@]}"; do
if [[ -z "${!var:-}" ]]; then
missing_vars+=("$var")
fi
done
if [[ ${#missing_vars[@]} -gt 0 ]]; then
log_error "Missing required environment variables:"
printf '%s\n' "${missing_vars[@]}"
exit 1
fi
log_success "Environment variables check passed"
}
# ========================================
# DATABASE OPERATIONS
# ========================================
create_backup() {
log_info "Creating database backup..."
mkdir -p "$BACKUP_DIR"
local backup_file="$BACKUP_DIR/backup_$TIMESTAMP.sql"
# Extract database info from DATABASE_URL
local db_container="math-postgres-prod"
if docker ps | grep -q "$db_container"; then
if docker exec "$db_container" pg_dump -U mathuser mathdb > "$backup_file"; then
log_success "Database backup created: $backup_file"
# Compress backup
gzip "$backup_file"
log_success "Backup compressed: ${backup_file}.gz"
# Keep only last 7 backups
ls -t "$BACKUP_DIR"/backup_*.sql.gz | tail -n +8 | xargs -r rm
else
log_warning "Failed to create database backup, continuing anyway..."
fi
else
log_warning "Database container not running, skipping backup"
fi
}
run_migrations() {
log_info "Running database migrations..."
cd "$PROJECT_DIR"
# Create temporary migration container
docker-compose -f docker-compose.prod.yml run --rm backend npx prisma migrate deploy
log_success "Database migrations completed"
}
# ========================================
# DEPLOYMENT OPERATIONS
# ========================================
build_images() {
log_info "Building Docker images..."
cd "$PROJECT_DIR"
# Export version for builds
export VERSION=${VERSION:-1.0.0}
# Build all images
docker-compose -f docker-compose.prod.yml build --no-cache
log_success "Docker images built successfully"
}
zero_downtime_deploy() {
log_info "Starting zero-downtime deployment..."
cd "$PROJECT_DIR"
# Scale up new instances
log_info "Scaling up backend instances..."
docker-compose -f docker-compose.prod.yml up -d --no-deps --scale backend=3 backend
# Wait for health checks
log_info "Waiting for health checks (30s)..."
sleep 30
# Check health
if ! check_service_health "backend"; then
log_error "Backend health check failed after scaling"
return 1
fi
# Scale down to normal
log_info "Scaling down to normal capacity..."
docker-compose -f docker-compose.prod.yml up -d --no-deps --scale backend=2 backend
log_success "Zero-downtime deployment completed"
}
deploy_services() {
log_info "Deploying services..."
cd "$PROJECT_DIR"
# Pull latest images if using registry
if [[ "${PULL_IMAGES:-false}" == "true" ]]; then
log_info "Pulling latest images from registry..."
docker-compose -f docker-compose.prod.yml pull
fi
# Deploy all services
docker-compose -f docker-compose.prod.yml up -d --remove-orphans
log_success "Services deployed successfully"
}
# ========================================
# HEALTH CHECKS
# ========================================
check_service_health() {
local service=$1
local max_attempts=${2:-10}
local attempt=1
log_info "Checking health for service: $service"
while [[ $attempt -le $max_attempts ]]; do
if docker-compose -f docker-compose.prod.yml ps "$service" | grep -q "healthy"; then
log_success "$service is healthy"
return 0
fi
log_info "Health check attempt $attempt/$max_attempts..."
sleep 5
((attempt++))
done
log_error "$service failed health check after $max_attempts attempts"
return 1
}
run_health_checks() {
log_info "Running comprehensive health checks..."
local services=("postgres" "redis" "backend" "frontend" "nginx")
local failed_services=()
for service in "${services[@]}"; do
if ! check_service_health "$service"; then
failed_services+=("$service")
fi
done
if [[ ${#failed_services[@]} -gt 0 ]]; then
log_error "Health checks failed for services:"
printf '%s\n' "${failed_services[@]}"
return 1
fi
# Check main health endpoint
local health_url="http://localhost/health"
if curl -sf "$health_url" &> /dev/null; then
log_success "Main health endpoint is responding"
else
log_warning "Main health endpoint not responding (might need SSL)"
fi
log_success "All health checks passed"
}
# ========================================
# ROLLBACK
# ========================================
rollback_deployment() {
log_warning "Initiating rollback..."
cd "$PROJECT_DIR"
# Get last successful version (if available)
local last_version=${LAST_VERSION:-"latest"}
# Revert to previous images
export VERSION="$last_version"
docker-compose -f docker-compose.prod.yml up -d
log_warning "Rollback completed"
}
# ========================================
# CLEANUP
# ========================================
cleanup() {
log_info "Running cleanup..."
# Remove old images
docker image prune -af --filter "until=24h" || true
# Remove unused volumes
docker volume prune -f || true
# Clean old logs
find "$LOG_DIR" -name "*.log" -type f -mtime +7 -delete 2>/dev/null || true
log_success "Cleanup completed"
}
# ========================================
# MAIN
# ========================================
main() {
log_info "🚀 Starting Math Platform Production Deployment"
log_info "Timestamp: $(date)"
log_info "Version: ${VERSION:-1.0.0}"
# Pre-deployment
check_prerequisites
check_environment
# Backup
create_backup
# Database
run_migrations
# Build and deploy
build_images
deploy_services
# Zero-downtime for backend
zero_downtime_deploy
# Verification
run_health_checks
# Cleanup
cleanup
log_success "✅ Deployment completed successfully!"
log_info "Services are running at:"
log_info " - Frontend: https://localhost"
log_info " - API: https://localhost/api"
log_info " - Grafana: http://localhost:3001 (if monitoring enabled)"
}
# Parse command line arguments
case "${1:-deploy}" in
"backup")
create_backup
;;
"migrate")
check_environment
run_migrations
;;
"rollback")
rollback_deployment
;;
"health")
run_health_checks
;;
"deploy"|*)
main
;;
esac