#!/bin/bash # ============================================ # DEPLOYMENT SCRIPT - PRODUCTION # Math Platform Docker Deployment # ============================================ set -euo pipefail # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color # ============================================ # CONFIGURATION # ============================================ COMPOSE_FILE="docker-compose.prod.yml" ENV_FILE=".env.prod" # ============================================ # FUNCTIONS # ============================================ log_info() { echo -e "${GREEN}[INFO]${NC} $1" } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1" } log_error() { echo -e "${RED}[ERROR]${NC} $1" } # ============================================ # PRE-FLIGHT CHECKS # ============================================ log_info "Verificando requisitos pre-deployment..." # Check Docker if ! command -v docker &> /dev/null; then log_error "Docker no está instalado" exit 1 fi # Check Docker Compose if ! command -v docker-compose &> /dev/null; then log_error "Docker Compose no está instalado" exit 1 fi # Check .env.prod exists if [[ ! -f "$ENV_FILE" ]]; then log_error "Archivo $ENV_FILE no encontrado" log_info "Copia .env.prod.example a .env.prod y configura los valores" exit 1 fi # Check directories exist mkdir -p pdfs/processed backups docker/ssl docker/logs # ============================================ # BUILD IMAGES # ============================================ log_info "Construyendo imágenes Docker..." docker-compose -f $COMPOSE_FILE --env-file $ENV_FILE build --no-cache # ============================================ # VERIFY CONFIGURATION # ============================================ log_info "Verificando configuración..." docker-compose -f $COMPOSE_FILE --env-file $ENV_FILE config > /dev/null # ============================================ # DEPLOY # ============================================ log_info "Iniciando deployment..." # Pull latest images for external services docker-compose -f $COMPOSE_FILE pull postgres redis nginx certbot # Start infrastructure first (database & cache) log_info "Iniciando infraestructura base..." docker-compose -f $COMPOSE_FILE --env-file $ENV_FILE up -d postgres redis # Wait for database to be healthy log_info "Esperando a que PostgreSQL esté listo..." sleep 10 # Start backend and workers log_info "Iniciando backend y workers..." docker-compose -f $COMPOSE_FILE --env-file $ENV_FILE up -d backend pdf-worker exercise-worker notification-worker # Wait for backend to be healthy log_info "Esperando a que el backend esté listo..." sleep 15 # Start frontend log_info "Iniciando frontend..." docker-compose -f $COMPOSE_FILE --env-file $ENV_FILE up -d frontend # Start nginx (reverse proxy) log_info "Iniciando Nginx..." docker-compose -f $COMPOSE_FILE --env-file $ENV_FILE up -d nginx certbot # ============================================ # HEALTH CHECK # ============================================ log_info "Verificando estado de los servicios..." sleep 5 # Check if all services are running SERVICES=("math-postgres-prod" "math-redis-prod" "math-nginx-prod") for service in "${SERVICES[@]}"; do if docker ps --format "{{.Names}}" | grep -q "^${service}$"; then log_info "✓ $service está corriendo" else log_error "✗ $service NO está corriendo" fi done # Check backend replicas BACKEND_COUNT=$(docker ps --format "{{.Names}}" | grep -c "math2_backend" || true) if [[ $BACKEND_COUNT -ge 2 ]]; then log_info "✓ Backend: $BACKEND_COUNT réplicas corriendo" else log_warn "⚠ Backend: Solo $BACKEND_COUNT réplica(s) corriendo (esperado: 2)" fi # Check frontend replicas FRONTEND_COUNT=$(docker ps --format "{{.Names}}" | grep -c "math2_frontend" || true) if [[ $FRONTEND_COUNT -ge 2 ]]; then log_info "✓ Frontend: $FRONTEND_COUNT réplicas corriendo" else log_warn "⚠ Frontend: Solo $FRONTEND_COUNT réplica(s) corriendo (esperado: 2)" fi # ============================================ # SSL CERTIFICATES # ============================================ log_info "Verificando certificados SSL..." if [[ -d "docker/ssl" ]] && [[ $(ls -A docker/ssl 2>/dev/null) ]]; then log_info "✓ Certificados SSL encontrados" else log_warn "⚠ No se encontraron certificados SSL en docker/ssl/" log_info "Para Let's Encrypt, ejecuta: docker-compose -f $COMPOSE_FILE run --rm certbot certonly" fi # ============================================ # COMPLETION # ============================================ log_info "============================================" log_info "DEPLOYMENT COMPLETADO EXITOSAMENTE" log_info "============================================" log_info "" log_info "URLs de acceso:" log_info " - Aplicación: https://localhost (o tu dominio)" log_info " - Health Check: http://localhost/health" log_info "" log_info "Comandos útiles:" log_info " - Ver logs: docker-compose -f $COMPOSE_FILE logs -f" log_info " - Escala backend: docker-compose -f $COMPOSE_FILE up -d --scale backend=3" log_info " - Reiniciar: docker-compose -f $COMPOSE_FILE restart" log_info " - Detener: docker-compose -f $COMPOSE_FILE down" log_info "" log_info "Monitoreo:" log_info " - Ver contenedores: docker ps" log_info " - Ver recursos: docker stats"