feat: añadir soporte Docker para despliegue

- 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
This commit is contained in:
planetazuzu 2025-12-21 18:03:55 +01:00
parent 1151ded301
commit 8ba7ed9734
5 changed files with 529 additions and 1 deletions

View file

@ -2,9 +2,254 @@
Esta guía explica cómo desplegar EMERGES TES en tu servidor propio con auto-actualización desde GitHub. 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) - **Servidor Linux** (Ubuntu/Debian recomendado)
- **Node.js 18+** instalado - **Node.js 18+** instalado

49
Dockerfile Normal file
View file

@ -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"]

160
deploy-docker.sh Executable file
View file

@ -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 ""

45
docker-compose.prod.yml Normal file
View file

@ -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

29
docker-compose.yml Normal file
View file

@ -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