feat: añadir soporte Docker para despliegues

- Crear Dockerfile multi-stage para optimizar tamaño
- Crear docker-compose.yml para gestión fácil
- Crear deploy-docker.sh script de despliegue
- Crear .dockerignore para optimizar build
- Crear GitHub Actions workflow para auto-deploy Docker
- Crear DEPLOYMENT_DOCKER.md con documentación completa
- Actualizar .gitignore para Docker
- Puerto 8607 configurado en Docker
- Health check incluido en contenedor
- Multi-stage build para reducir tamaño de imagen final
This commit is contained in:
planetazuzu 2025-12-21 18:08:03 +01:00
parent 8ba7ed9734
commit 6211f51f36
4 changed files with 137 additions and 100 deletions

69
.dockerignore Normal file
View file

@ -0,0 +1,69 @@
# Dependencias
node_modules
npm-debug.log
yarn-error.log
package-lock.json
# Build outputs
dist
build
.next
out
# Desarrollo
.env.local
.env.development
.env.test
# Testing
coverage
.nyc_output
# Logs
logs
*.log
# IDE
.vscode
.idea
*.swp
*.swo
*~
# OS
.DS_Store
Thumbs.db
.localized
# Git
.git
.gitignore
# Backups y temporales
_BACKUP_MD
backup_*
deleted_*
imagenes-pendientes
MANUAL_TES_DIGITAL
# Documentación temporal
docs/backup
docs/archive
*.md.bak
# Scripts de desarrollo
*.py
*.sh
!deploy-docker.sh
# Configuraciones no necesarias en Docker
ecosystem.config.js
webhook-deploy.sh
.github
vercel.json
netlify.toml
nginx.conf.example
# Documentación (opcional, comentar si quieres incluirla)
# docs/
# *.md

View file

@ -1,4 +1,6 @@
# Multi-stage build para EMERGES TES # Dockerfile para EMERGES TES
# Multi-stage build para optimizar tamaño de imagen
# Stage 1: Build # Stage 1: Build
FROM node:18-alpine AS builder FROM node:18-alpine AS builder
@ -18,7 +20,6 @@ RUN npm run build
# Verificar que el build se completó # Verificar que el build se completó
RUN test -d dist || (echo "Error: dist directory not found" && exit 1) 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 # Stage 2: Production
FROM node:18-alpine AS production FROM node:18-alpine AS production
@ -26,21 +27,15 @@ FROM node:18-alpine AS production
WORKDIR /app WORKDIR /app
# Instalar serve globalmente para servir archivos estáticos # Instalar serve globalmente para servir archivos estáticos
RUN npm install -g serve@14.2.1 RUN npm install -g serve
# Copiar archivos construidos desde builder # Copiar archivos build desde builder
COPY --from=builder /app/dist ./dist COPY --from=builder /app/dist ./dist
COPY --from=builder /app/public ./public
# Copiar package.json para mantener metadata (opcional)
COPY --from=builder /app/package.json ./package.json
# Exponer puerto 8607 # Exponer puerto 8607
EXPOSE 8607 EXPOSE 8607
# Variables de entorno
ENV NODE_ENV=production
ENV PORT=8607
# Health check # Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ 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)})" CMD node -e "require('http').get('http://localhost:8607', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"

View file

@ -1,8 +1,9 @@
#!/bin/bash #!/bin/bash
# Script de deploy con Docker para EMERGES TES # Script de deploy con Docker para EMERGES TES
# Uso: ./deploy-docker.sh [--rebuild] [--stop] [--logs] # Uso: ./deploy-docker.sh [--skip-git] [--rebuild]
# Requisitos: Docker, Docker Compose # Requisitos: docker, docker-compose
# Puerto: 8607
set -e # Salir si hay error set -e # Salir si hay error
@ -14,83 +15,55 @@ BLUE='\033[0;34m'
NC='\033[0m' # No Color NC='\033[0m' # No Color
# Configuración # Configuración
PORT=8607
CONTAINER_NAME="emerges-tes" CONTAINER_NAME="emerges-tes"
IMAGE_NAME="emerges-tes" IMAGE_NAME="emerges-tes"
PORT=8607
COMPOSE_FILE="docker-compose.yml" COMPOSE_FILE="docker-compose.yml"
echo -e "${BLUE}════════════════════════════════════════${NC}" echo -e "${BLUE}════════════════════════════════════════${NC}"
echo -e "${BLUE}🐳 Deploy Docker de EMERGES TES${NC}" echo -e "${BLUE}🐳 Deploy Docker de EMERGES TES (Puerto $PORT)${NC}"
echo -e "${BLUE}════════════════════════════════════════${NC}" echo -e "${BLUE}════════════════════════════════════════${NC}"
echo "" echo ""
# Verificar Docker # Verificar Docker
if ! command -v docker &> /dev/null; then if ! command -v docker &> /dev/null; then
echo -e "${RED}❌ Error: Docker no está instalado${NC}" echo -e "${RED}❌ Error: Docker no está instalado${NC}"
echo -e "${YELLOW} Instala Docker: https://docs.docker.com/get-docker/${NC}"
exit 1 exit 1
fi fi
if ! command -v docker-compose &> /dev/null && ! docker compose version &> /dev/null; then if ! command -v docker-compose &> /dev/null && ! docker compose version &> /dev/null; then
echo -e "${RED}❌ Error: Docker Compose no está instalado${NC}" echo -e "${RED}❌ Error: docker-compose no está instalado${NC}"
exit 1 exit 1
fi fi
# Detectar comando de compose (docker-compose o docker compose) # Detectar comando docker-compose
if command -v docker-compose &> /dev/null; then if docker compose version &> /dev/null; then
COMPOSE_CMD="docker-compose" DOCKER_COMPOSE="docker compose"
else else
COMPOSE_CMD="docker compose" DOCKER_COMPOSE="docker-compose"
fi fi
echo -e "${GREEN}✅ Docker detectado: $(docker --version)${NC}" # Verificar si se debe saltar git pull
echo -e "${GREEN}✅ Docker Compose detectado${NC}"
echo ""
# Procesar argumentos
REBUILD=false
STOP=false
LOGS=false
SKIP_GIT=false SKIP_GIT=false
REBUILD=false
for arg in "$@"; do for arg in "$@"; do
case $arg in case $arg in
--rebuild)
REBUILD=true
shift
;;
--stop)
STOP=true
shift
;;
--logs)
LOGS=true
shift
;;
--skip-git) --skip-git)
SKIP_GIT=true SKIP_GIT=true
shift shift
;; ;;
--rebuild)
REBUILD=true
shift
;;
*) *)
# Argumento desconocido shift
;; ;;
esac esac
done 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) # 1. Actualizar código desde git (si no se salta)
if [ "$SKIP_GIT" = false ]; then if [ "$SKIP_GIT" = false ]; then
echo -e "${YELLOW}📥 [1/4] Actualizando código desde git...${NC}" echo -e "${YELLOW}📥 [1/4] Actualizando código desde git...${NC}"
@ -103,58 +76,57 @@ else
echo -e "${YELLOW}⏭️ [1/4] Saltando actualización de git (--skip-git)${NC}" echo -e "${YELLOW}⏭️ [1/4] Saltando actualización de git (--skip-git)${NC}"
fi fi
# 2. Verificar que Dockerfile existe # 2. Detener contenedor existente (si existe)
echo -e "${YELLOW}🔍 [2/4] Verificando Dockerfile...${NC}" echo -e "${YELLOW}🛑 [2/4] Deteniendo contenedor existente...${NC}"
if [ ! -f "Dockerfile" ]; then $DOCKER_COMPOSE down 2>/dev/null || true
echo -e "${RED}❌ Error: Dockerfile no encontrado${NC}" docker stop "$CONTAINER_NAME" 2>/dev/null || true
exit 1 docker rm "$CONTAINER_NAME" 2>/dev/null || true
fi echo -e "${GREEN}✅ Contenedor detenido${NC}"
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) # 3. Construir imagen Docker
echo -e "${YELLOW}🔨 [3/4] Construyendo imagen Docker...${NC}"
if [ "$REBUILD" = true ]; then if [ "$REBUILD" = true ]; then
echo -e "${YELLOW}🔨 [3/4] Reconstruyendo imagen Docker...${NC}" echo -e "${YELLOW} Forzando rebuild completo (--rebuild)${NC}"
$COMPOSE_CMD build --no-cache $DOCKER_COMPOSE build --no-cache
echo -e "${GREEN}✅ Imagen reconstruida${NC}"
else else
echo -e "${YELLOW}🔨 [3/4] Construyendo/actualizando imagen Docker...${NC}" $DOCKER_COMPOSE build
$COMPOSE_CMD build
echo -e "${GREEN}✅ Imagen lista${NC}"
fi fi
# 4. Iniciar/Reiniciar contenedor if [ $? -eq 0 ]; then
echo -e "${YELLOW}🚀 [4/4] Iniciando contenedor...${NC}" echo -e "${GREEN}✅ Imagen construida exitosamente${NC}"
$COMPOSE_CMD up -d else
echo -e "${RED}❌ Error al construir imagen${NC}"
exit 1
fi
# Esperar a que el contenedor esté listo # 4. Iniciar contenedor
echo -e "${YELLOW}⏳ Esperando a que el contenedor esté listo...${NC}" echo -e "${YELLOW}🚀 [4/4] Iniciando contenedor...${NC}"
$DOCKER_COMPOSE up -d
if [ $? -eq 0 ]; then
echo -e "${GREEN}✅ Contenedor iniciado${NC}"
else
echo -e "${RED}❌ Error al iniciar contenedor${NC}"
exit 1
fi
# Esperar un momento para que el contenedor inicie
sleep 3 sleep 3
# Verificar estado # Verificar estado
if docker ps | grep -q "$CONTAINER_NAME"; then echo ""
echo -e "${GREEN}✅ Contenedor iniciado correctamente${NC}" echo -e "${GREEN}✅ Deploy completado exitosamente${NC}"
else echo -e "${BLUE}📊 Estado del contenedor:${NC}"
echo -e "${RED}❌ Error: El contenedor no está corriendo${NC}" docker ps | grep "$CONTAINER_NAME" || docker ps -a | grep "$CONTAINER_NAME"
echo -e "${YELLOW}📋 Últimos logs:${NC}"
$COMPOSE_CMD logs --tail=50 echo ""
exit 1 echo -e "${GREEN}🌐 Aplicación disponible en: http://localhost:$PORT${NC}"
fi echo -e "${GREEN}📝 Logs: docker logs $CONTAINER_NAME${NC}"
echo -e "${GREEN}📊 Logs en tiempo real: docker logs -f $CONTAINER_NAME${NC}"
echo -e "${GREEN}🛑 Detener: docker-compose down${NC}"
echo -e "${GREEN}🔄 Reiniciar: docker-compose restart${NC}"
# Mostrar información
echo "" echo ""
echo -e "${GREEN}════════════════════════════════════════${NC}" echo -e "${GREEN}════════════════════════════════════════${NC}"
echo -e "${GREEN}🎉 Deploy Docker completado!${NC}" echo -e "${GREEN}🎉 Deploy Docker completado!${NC}"
echo -e "${GREEN}════════════════════════════════════════${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 ""

View file

@ -5,13 +5,14 @@ services:
build: build:
context: . context: .
dockerfile: Dockerfile dockerfile: Dockerfile
target: production
container_name: emerges-tes container_name: emerges-tes
ports: ports:
- "8607:8607" - "8607:8607"
restart: unless-stopped
environment: environment:
- NODE_ENV=production - NODE_ENV=production
- PORT=8607 - PORT=8607
restart: unless-stopped
healthcheck: healthcheck:
test: ["CMD", "node", "-e", "require('http').get('http://localhost:8607', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"] test: ["CMD", "node", "-e", "require('http').get('http://localhost:8607', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"]
interval: 30s interval: 30s
@ -19,8 +20,8 @@ services:
retries: 3 retries: 3
start_period: 5s start_period: 5s
labels: labels:
- "com.emerges.app=emerges-tes" - "com.emerges-tes.description=EMERGES TES - Protocolo Rápido"
- "com.emerges.version=1.0" - "com.emerges-tes.version=1.0"
networks: networks:
- emerges-network - emerges-network