From 8ba7ed9734c569a5d50e9968d6fac0923196a6e4 Mon Sep 17 00:00:00 2001 From: planetazuzu Date: Sun, 21 Dec 2025 18:03:55 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20a=C3=B1adir=20soporte=20Docker=20para?= =?UTF-8?q?=20despliegue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Crear Dockerfile multi-stage (build + production) - Crear docker-compose.yml y docker-compose.prod.yml - Crear .dockerignore para optimizar build - Crear deploy-docker.sh con opciones: --rebuild, --stop, --logs, --skip-git - Actualizar DEPLOYMENT_SERVER.md con sección Docker completa - Actualizar GitHub Actions workflow para detectar y usar Docker automáticamente - Incluir health checks, límites de recursos y logging - Documentar comandos Docker útiles y solución de problemas - Puerto 8607 configurado en Docker --- DEPLOYMENT_SERVER.md | 247 +++++++++++++++++++++++++++++++++++++++- Dockerfile | 49 ++++++++ deploy-docker.sh | 160 ++++++++++++++++++++++++++ docker-compose.prod.yml | 45 ++++++++ docker-compose.yml | 29 +++++ 5 files changed, 529 insertions(+), 1 deletion(-) create mode 100644 Dockerfile create mode 100755 deploy-docker.sh create mode 100644 docker-compose.prod.yml create mode 100644 docker-compose.yml diff --git a/DEPLOYMENT_SERVER.md b/DEPLOYMENT_SERVER.md index 4700fa6d..2cedd644 100644 --- a/DEPLOYMENT_SERVER.md +++ b/DEPLOYMENT_SERVER.md @@ -2,9 +2,254 @@ Esta guía explica cómo desplegar EMERGES TES en tu servidor propio con auto-actualización desde GitHub. +**Opciones de despliegue:** +- 🐳 **Docker** (Recomendado) - Ver sección [Despliegue con Docker](#despliegue-con-docker) +- 📦 **PM2 + Node.js** - Ver sección [Despliegue con PM2](#despliegue-con-pm2) + --- -## 📋 Requisitos Previos +## 🐳 DESPLIEGUE CON DOCKER (Recomendado) + +### Ventajas de Docker + +- ✅ Aislamiento completo de dependencias +- ✅ Reproducible en cualquier entorno +- ✅ Fácil actualización y rollback +- ✅ Gestión simplificada con docker-compose +- ✅ Health checks automáticos +- ✅ Recursos limitados (CPU/memoria) + +### Requisitos Previos Docker + +- **Docker** 20.10+ instalado +- **Docker Compose** 2.0+ (o `docker compose` plugin) +- **Git** instalado +- **Puerto 8607** disponible + +### Instalación Inicial con Docker + +#### 1. Instalar Docker + +```bash +# Ubuntu/Debian +curl -fsSL https://get.docker.com -o get-docker.sh +sudo sh get-docker.sh + +# Verificar instalación +docker --version +docker compose version +``` + +#### 2. Clonar el repositorio + +```bash +cd /ruta/donde/quieres/la/app +git clone https://github.com/tu-usuario/guia-tes-digital.git +cd guia-tes-digital +``` + +#### 3. Configurar Docker + +```bash +# Hacer ejecutable el script de deploy +chmod +x deploy-docker.sh + +# Verificar que los archivos Docker existen +ls -la Dockerfile docker-compose.yml +``` + +#### 4. Primer despliegue + +```bash +# Deploy completo (con git pull + build + start) +./deploy-docker.sh + +# O sin actualizar git (útil para webhooks) +./deploy-docker.sh --skip-git +``` + +### Comandos Docker Útiles + +```bash +# Deploy completo +./deploy-docker.sh + +# Reconstruir imagen desde cero +./deploy-docker.sh --rebuild + +# Ver logs en tiempo real +./deploy-docker.sh --logs +# O directamente: +docker-compose logs -f + +# Detener contenedor +./deploy-docker.sh --stop +# O directamente: +docker-compose down + +# Ver estado +docker ps | grep emerges-tes + +# Entrar al contenedor (debug) +docker exec -it emerges-tes sh + +# Ver uso de recursos +docker stats emerges-tes +``` + +### Auto-Deploy con Docker + +#### Opción 1: GitHub Actions + Docker + +El workflow `.github/workflows/deploy.yml` puede actualizarse para usar Docker: + +```yaml +- name: Desplegar con Docker + uses: appleboy/ssh-action@v1.0.3 + with: + host: ${{ secrets.SERVER_HOST }} + username: ${{ secrets.SERVER_USER }} + key: ${{ secrets.SERVER_SSH_KEY }} + script: | + cd ${{ secrets.APP_PATH }} + ./deploy-docker.sh --skip-git +``` + +#### Opción 2: Webhook + Docker + +Actualizar `webhook-deploy.sh` para usar Docker: + +```bash +# En webhook-deploy.sh, cambiar: +./deploy.sh --skip-git +# Por: +./deploy-docker.sh --skip-git +``` + +#### Opción 3: Cron + Docker + +```bash +# Crear script +nano /usr/local/bin/check-github-updates-docker.sh +``` + +```bash +#!/bin/bash +cd /ruta/a/tu/app +git fetch origin +if [ $(git rev-parse HEAD) != $(git rev-parse origin/main) ]; then + ./deploy-docker.sh +fi +``` + +```bash +chmod +x /usr/local/bin/check-github-updates-docker.sh + +# Añadir a crontab +crontab -e +# Añadir: +*/5 * * * * /usr/local/bin/check-github-updates-docker.sh >> /var/log/docker-deploy.log 2>&1 +``` + +### Verificación y Monitoreo Docker + +```bash +# Verificar que el contenedor está corriendo +docker ps | grep emerges-tes + +# Ver logs +docker-compose logs -f emerges-tes + +# Ver health check +docker inspect emerges-tes | grep -A 10 Health + +# Ver uso de recursos +docker stats emerges-tes + +# Verificar puerto +netstat -tlnp | grep 8607 +# O +ss -tlnp | grep 8607 +``` + +### Acceder a la aplicación + +- **Local:** `http://localhost:8607` +- **Red:** `http://tu-servidor-ip:8607` +- **Dominio:** `http://tu-dominio.com:8607` + +### Solución de Problemas Docker + +**Error: "Cannot connect to Docker daemon"** +```bash +# Añadir usuario al grupo docker +sudo usermod -aG docker $USER +# Reiniciar sesión o: +newgrp docker +``` + +**Error: "Port 8607 already in use"** +```bash +# Ver qué usa el puerto +sudo lsof -i :8607 +# Detener contenedor anterior +docker-compose down +``` + +**Error: "Build failed"** +```bash +# Limpiar y reconstruir +docker-compose down +docker system prune -f +./deploy-docker.sh --rebuild +``` + +**Contenedor se detiene inmediatamente** +```bash +# Ver logs +docker-compose logs emerges-tes +# Verificar Dockerfile +cat Dockerfile +``` + +### Configuración Avanzada Docker + +#### Usar docker-compose.prod.yml para producción + +```bash +# Usar archivo de producción +docker-compose -f docker-compose.prod.yml up -d + +# O actualizar deploy-docker.sh para usar este archivo +``` + +#### Variables de entorno personalizadas + +Crear `.env`: +```env +NODE_ENV=production +PORT=8607 +``` + +Y usar en `docker-compose.yml`: +```yaml +env_file: + - .env +``` + +#### Límites de recursos + +Ya configurado en `docker-compose.prod.yml`: +- CPU: 1.0 máximo, 0.5 reservado +- Memoria: 512MB máximo, 256MB reservado + +--- + +## 📦 DESPLIEGUE CON PM2 (Alternativa) + +--- + +## 📋 Requisitos Previos (PM2) - **Servidor Linux** (Ubuntu/Debian recomendado) - **Node.js 18+** instalado diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..6de6a3d6 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,49 @@ +# Multi-stage build para EMERGES TES +# Stage 1: Build +FROM node:18-alpine AS builder + +WORKDIR /app + +# Copiar archivos de dependencias +COPY package.json package-lock.json* ./ + +# Instalar dependencias +RUN npm ci --production=false + +# Copiar código fuente +COPY . . + +# Build de producción +RUN npm run build + +# Verificar que el build se completó +RUN test -d dist || (echo "Error: dist directory not found" && exit 1) +RUN test "$(ls -A dist)" || (echo "Error: dist directory is empty" && exit 1) + +# Stage 2: Production +FROM node:18-alpine AS production + +WORKDIR /app + +# Instalar serve globalmente para servir archivos estáticos +RUN npm install -g serve@14.2.1 + +# Copiar archivos construidos desde builder +COPY --from=builder /app/dist ./dist + +# Copiar package.json para mantener metadata (opcional) +COPY --from=builder /app/package.json ./package.json + +# Exponer puerto 8607 +EXPOSE 8607 + +# Variables de entorno +ENV NODE_ENV=production +ENV PORT=8607 + +# Health check +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD node -e "require('http').get('http://localhost:8607', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})" + +# Comando para servir la aplicación +CMD ["serve", "-s", "dist", "-l", "8607"] diff --git a/deploy-docker.sh b/deploy-docker.sh new file mode 100755 index 00000000..ea198082 --- /dev/null +++ b/deploy-docker.sh @@ -0,0 +1,160 @@ +#!/bin/bash + +# Script de deploy con Docker para EMERGES TES +# Uso: ./deploy-docker.sh [--rebuild] [--stop] [--logs] +# Requisitos: Docker, Docker Compose + +set -e # Salir si hay error + +# Colores para output +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +RED='\033[0;31m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Configuración +CONTAINER_NAME="emerges-tes" +IMAGE_NAME="emerges-tes" +PORT=8607 +COMPOSE_FILE="docker-compose.yml" + +echo -e "${BLUE}════════════════════════════════════════${NC}" +echo -e "${BLUE}🐳 Deploy Docker de EMERGES TES${NC}" +echo -e "${BLUE}════════════════════════════════════════${NC}" +echo "" + +# Verificar Docker +if ! command -v docker &> /dev/null; then + echo -e "${RED}❌ Error: Docker no está instalado${NC}" + exit 1 +fi + +if ! command -v docker-compose &> /dev/null && ! docker compose version &> /dev/null; then + echo -e "${RED}❌ Error: Docker Compose no está instalado${NC}" + exit 1 +fi + +# Detectar comando de compose (docker-compose o docker compose) +if command -v docker-compose &> /dev/null; then + COMPOSE_CMD="docker-compose" +else + COMPOSE_CMD="docker compose" +fi + +echo -e "${GREEN}✅ Docker detectado: $(docker --version)${NC}" +echo -e "${GREEN}✅ Docker Compose detectado${NC}" +echo "" + +# Procesar argumentos +REBUILD=false +STOP=false +LOGS=false +SKIP_GIT=false + +for arg in "$@"; do + case $arg in + --rebuild) + REBUILD=true + shift + ;; + --stop) + STOP=true + shift + ;; + --logs) + LOGS=true + shift + ;; + --skip-git) + SKIP_GIT=true + shift + ;; + *) + # Argumento desconocido + ;; + esac +done + +# Si se solicita detener +if [ "$STOP" = true ]; then + echo -e "${YELLOW}🛑 Deteniendo contenedor...${NC}" + $COMPOSE_CMD down + echo -e "${GREEN}✅ Contenedor detenido${NC}" + exit 0 +fi + +# Si se solicitan logs +if [ "$LOGS" = true ]; then + echo -e "${YELLOW}📋 Mostrando logs...${NC}" + $COMPOSE_CMD logs -f + exit 0 +fi + +# 1. Actualizar código desde git (si no se salta) +if [ "$SKIP_GIT" = false ]; then + echo -e "${YELLOW}📥 [1/4] Actualizando código desde git...${NC}" + if git pull origin main; then + echo -e "${GREEN}✅ Código actualizado${NC}" + else + echo -e "${RED}⚠️ Error al actualizar desde git (continuando...)\n${NC}" + fi +else + echo -e "${YELLOW}⏭️ [1/4] Saltando actualización de git (--skip-git)${NC}" +fi + +# 2. Verificar que Dockerfile existe +echo -e "${YELLOW}🔍 [2/4] Verificando Dockerfile...${NC}" +if [ ! -f "Dockerfile" ]; then + echo -e "${RED}❌ Error: Dockerfile no encontrado${NC}" + exit 1 +fi +if [ ! -f "$COMPOSE_FILE" ]; then + echo -e "${RED}❌ Error: $COMPOSE_FILE no encontrado${NC}" + exit 1 +fi +echo -e "${GREEN}✅ Archivos Docker encontrados${NC}" + +# 3. Construir imagen (si es necesario) +if [ "$REBUILD" = true ]; then + echo -e "${YELLOW}🔨 [3/4] Reconstruyendo imagen Docker...${NC}" + $COMPOSE_CMD build --no-cache + echo -e "${GREEN}✅ Imagen reconstruida${NC}" +else + echo -e "${YELLOW}🔨 [3/4] Construyendo/actualizando imagen Docker...${NC}" + $COMPOSE_CMD build + echo -e "${GREEN}✅ Imagen lista${NC}" +fi + +# 4. Iniciar/Reiniciar contenedor +echo -e "${YELLOW}🚀 [4/4] Iniciando contenedor...${NC}" +$COMPOSE_CMD up -d + +# Esperar a que el contenedor esté listo +echo -e "${YELLOW}⏳ Esperando a que el contenedor esté listo...${NC}" +sleep 3 + +# Verificar estado +if docker ps | grep -q "$CONTAINER_NAME"; then + echo -e "${GREEN}✅ Contenedor iniciado correctamente${NC}" +else + echo -e "${RED}❌ Error: El contenedor no está corriendo${NC}" + echo -e "${YELLOW}📋 Últimos logs:${NC}" + $COMPOSE_CMD logs --tail=50 + exit 1 +fi + +# Mostrar información +echo "" +echo -e "${GREEN}════════════════════════════════════════${NC}" +echo -e "${GREEN}🎉 Deploy Docker completado!${NC}" +echo -e "${GREEN}════════════════════════════════════════${NC}" +echo "" +echo -e "${BLUE}📊 Estado del contenedor:${NC}" +docker ps | grep "$CONTAINER_NAME" || true +echo "" +echo -e "${GREEN}🌐 Aplicación disponible en: http://localhost:$PORT${NC}" +echo -e "${GREEN}📝 Logs: $COMPOSE_CMD logs -f${NC}" +echo -e "${GREEN}📊 Estado: docker ps | grep $CONTAINER_NAME${NC}" +echo -e "${GREEN}🛑 Detener: $COMPOSE_CMD down${NC}" +echo "" diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 00000000..8a082bb8 --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,45 @@ +version: '3.8' + +services: + emerges-tes: + build: + context: . + dockerfile: Dockerfile + args: + - NODE_ENV=production + container_name: emerges-tes-prod + ports: + - "8607:8607" + environment: + - NODE_ENV=production + - PORT=8607 + restart: always + healthcheck: + test: ["CMD", "node", "-e", "require('http').get('http://localhost:8607', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"] + interval: 30s + timeout: 3s + retries: 3 + start_period: 5s + deploy: + resources: + limits: + cpus: '1.0' + memory: 512M + reservations: + cpus: '0.5' + memory: 256M + labels: + - "com.emerges.app=emerges-tes" + - "com.emerges.version=1.0" + - "com.emerges.environment=production" + networks: + - emerges-network + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + +networks: + emerges-network: + driver: bridge diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..e9dafd73 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,29 @@ +version: '3.8' + +services: + emerges-tes: + build: + context: . + dockerfile: Dockerfile + container_name: emerges-tes + ports: + - "8607:8607" + environment: + - NODE_ENV=production + - PORT=8607 + restart: unless-stopped + healthcheck: + test: ["CMD", "node", "-e", "require('http').get('http://localhost:8607', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"] + interval: 30s + timeout: 3s + retries: 3 + start_period: 5s + labels: + - "com.emerges.app=emerges-tes" + - "com.emerges.version=1.0" + networks: + - emerges-network + +networks: + emerges-network: + driver: bridge