diff --git a/.env.example b/.env.example index b413355..e353bc2 100644 --- a/.env.example +++ b/.env.example @@ -2,6 +2,16 @@ # Copy this file to .env and fill in your actual values # DO NOT commit .env to version control +# === Project Configuration === +# Nombre del proyecto (usado para prefijos de contenedores y redes) +# Para múltiples instancias, usa nombres diferentes: instancia1, instancia2, etc. +# Por defecto: onedrive +# COMPOSE_PROJECT_NAME=onedrive + +# Puerto expuesto para el motor (por defecto: 8089) +# Para múltiples instancias, usa puertos diferentes: 8089, 8090, 8091, etc. +# ENGINE_PORT=8089 + # === Engine (odengin) Configuration === # Microsoft Azure credentials E5_CLIENT_ID=your_client_id_here @@ -13,8 +23,8 @@ WEB_APP_PASSWORD=your_secure_password_here E5_WEB_APP_PASSWORD=your_e5_password_here # === Cron Service (odcron) Configuration === -# Engine connection -CRON_IP=odengin:8080 +# Engine connection (se genera automáticamente si no se especifica) +# CRON_IP=odengin:8080 # Authentication CRON_PASSWORD=your_cron_password_here diff --git a/MULTI_INSTANCIAS.md b/MULTI_INSTANCIAS.md new file mode 100644 index 0000000..d5a4abb --- /dev/null +++ b/MULTI_INSTANCIAS.md @@ -0,0 +1,306 @@ +# 🚀 Ejecutar Múltiples Instancias + +Este proyecto está configurado para ejecutar múltiples instancias en la misma máquina sin conflictos de puertos o nombres. + +## 📋 Estructura de Directorios + +Para ejecutar múltiples instancias, organiza el proyecto así: + +``` +OneDrive/ +├── instancia1/ # Primera instancia +│ ├── .env +│ └── docker-compose.yml (enlace simbólico o copia) +├── instancia2/ # Segunda instancia +│ ├── .env +│ └── docker-compose.yml (enlace simbólico o copia) +└── instancia3/ # Tercera instancia + ├── .env + └── docker-compose.yml (enlace simbólico o copia) +``` + +## 🔧 Configuración para Múltiples Instancias + +### Opción 1: Directorios Separados (Recomendado) + +**Paso 1: Crea directorios para cada instancia** + +```powershell +# Windows +mkdir instancia1, instancia2, instancia3 + +# o crear estructura completa +mkdir instancia1\engine, instancia1\cron +mkdir instancia2\engine, instancia2\cron +mkdir instancia3\engine, instancia3\cron +``` + +**Paso 2: Copia el proyecto a cada directorio** + +```powershell +# Copiar archivos base +Copy-Item -Path "docker-compose.yml", ".env.example", ".gitignore" -Destination "instancia1" +Copy-Item -Path "docker-compose.yml", ".env.example", ".gitignore" -Destination "instancia2" +Copy-Item -Path "docker-compose.yml", ".env.example", ".gitignore" -Destination "instancia3" + +# Copiar carpetas engine y cron +Copy-Item -Path "engine\*" -Destination "instancia1\engine" -Recurse +Copy-Item -Path "cron\*" -Destination "instancia1\cron" -Recurse + +# Repetir para instancia2 y instancia3 +``` + +**Paso 3: Crea archivos `.env` para cada instancia** + +```powershell +# Instancia 1 +cd instancia1 +cp .env.example .env +# Editar .env con credenciales de cuenta 1 + +# Instancia 2 +cd ..\instancia2 +cp .env.example .env +# Editar .env con credenciales de cuenta 2 + +# Instancia 3 +cd ..\instancia3 +cp .env.example .env +# Editar .env con credenciales de cuenta 3 +``` + +**Contenido del `.env` para cada instancia:** + +```env +# instancia1/.env +COMPOSE_PROJECT_NAME=instancia1 +ENGINE_PORT=8089 +E5_CLIENT_ID=cuenta1_client_id +E5_CLIENT_SECRET=cuenta1_secret +E5_REFRESH_TOKEN=cuenta1_refresh_token +WEB_APP_PASSWORD=password1 +E5_WEB_APP_PASSWORD=e5_password1 +CRON_PASSWORD=cron_password1 +CRON_REFRESH_TOKEN=cron_refresh_token1 +``` + +```env +# instancia2/.env +COMPOSE_PROJECT_NAME=instancia2 +ENGINE_PORT=8090 +E5_CLIENT_ID=cuenta2_client_id +E5_CLIENT_SECRET=cuenta2_secret +E5_REFRESH_TOKEN=cuenta2_refresh_token +WEB_APP_PASSWORD=password2 +E5_WEB_APP_PASSWORD=e5_password2 +CRON_PASSWORD=cron_password2 +CRON_REFRESH_TOKEN=cron_refresh_token2 +``` + +```env +# instancia3/.env +COMPOSE_PROJECT_NAME=instancia3 +ENGINE_PORT=8091 +E5_CLIENT_ID=cuenta3_client_id +E5_CLIENT_SECRET=cuenta3_secret +E5_REFRESH_TOKEN=cuenta3_refresh_token +WEB_APP_PASSWORD=password3 +E5_WEB_APP_PASSWORD=e5_password3 +CRON_PASSWORD=cron_password3 +CRON_REFRESH_TOKEN=cron_refresh_token3 +``` + +### Opción 2: Una Sola Carpeta con Múltiples `.env` + +Si prefieres mantener un solo directorio, usa `.env` personalizados: + +```powershell +# Crear archivos .env específicos +cp .env.example .env.instancia1 +cp .env.example .env.instancia2 +cp .env.example .env.instancia3 +``` + +**Comando para lanzar:** + +```powershell +# Instancia 1 +docker-compose -p instancia1 --env-file .env.instancia1 up -d + +# Instancia 2 +docker-compose -p instancia2 --env-file .env.instancia2 up -d + +# Instancia 3 +docker-compose -p instancia3 --env-file .env.instancia3 up -d +``` + +## 🎯 Gestión de Múltiples Instancias + +### Iniciar todas las instancias + +```powershell +# Opción 1: Directorios separados +cd instancia1; docker-compose up -d; cd .. +cd instancia2; docker-compose up -d; cd .. +cd instancia3; docker-compose up -d; cd .. + +# Opción 2: Script PowerShell +@("instancia1", "instancia2", "instancia3") | ForEach-Object { + Write-Host "Iniciando $_..." + Push-Location $_ + docker-compose up -d + Pop-Location +} +``` + +### Ver estado de todas las instancias + +```powershell +# Opción 1: Por instancia +cd instancia1; docker-compose ps; cd .. +cd instancia2; docker-compose ps; cd .. +cd instancia3; docker-compose ps; cd .. + +# Opción 2: Comando único +docker ps --filter "label=com.docker.compose.project" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" +``` + +### Ver logs de una instancia + +```powershell +cd instancia1 +docker-compose logs -f odengin +docker-compose logs -f odcron +``` + +### Detener todas las instancias + +```powershell +@("instancia1", "instancia2", "instancia3") | ForEach-Object { + Write-Host "Deteniendo $_..." + Push-Location $_ + docker-compose down + Pop-Location +} +``` + +### Reiniciar una instancia + +```powershell +cd instancia2 +docker-compose restart +``` + +## 📊 Tabla de Puertos Recomendados + +| Instancia | Puerto Motor | Contenedor Engine | Contenedor Cron | +|-----------|-------------|-------------------|-----------------| +| instancia1 | 8089 | instancia1-odengin | instancia1-odcron | +| instancia2 | 8090 | instancia2-odengin | instancia2-odcron | +| instancia3 | 8091 | instancia3-odengin | instancia3-odcron | +| instancia4 | 8092 | instancia4-odengin | instancia4-odcron | + +## 🔗 Cómo Funcionan las Variables de Entorno + +El `docker-compose.yml` usa variables para ser flexible: + +| Variable | Uso | Valor Por Defecto | +|----------|-----|-------------------| +| `COMPOSE_PROJECT_NAME` | Prefijo de nombres y redes | `onedrive` | +| `ENGINE_PORT` | Puerto expuesto del motor | `8089` | +| `CRON_IP` | Dirección del motor para cron | `{COMPOSE_PROJECT_NAME}-odengin:8080` | + +### Ejemplo de Expansión + +Con `COMPOSE_PROJECT_NAME=instancia1` y `ENGINE_PORT=8089`: + +```yaml +container_name: instancia1-odengin +ports: ["8089:8080"] +hostname: instancia1-odengin +networks: + - instancia1-net +``` + +## 🚨 Solución de Problemas + +### Error: "Port is already in use" + +**Causa:** Dos instancias intentan usar el mismo puerto. + +**Solución:** Verifica que cada instancia tenga un `ENGINE_PORT` único en su `.env`: + +```powershell +# Ver qué puertos están en uso +docker ps --format "table {{.Names}}\t{{.Ports}}" + +# Ver un puerto específico +netstat -ano | findstr :8089 +``` + +### Error: "Container name is already in use" + +**Causa:** Docker intenta crear un contenedor con nombre duplicado. + +**Solución:** Verifica que cada instancia tenga un `COMPOSE_PROJECT_NAME` único. + +### Los contenedores se detienen solos + +**Causa:** Probablemente hay un error en el script Python. + +**Solución:** Revisa los logs: + +```powershell +docker-compose logs -f odengin +docker-compose logs -f odcron +``` + +## 💡 Tips + +1. **Usa nombres descriptivos:** `cuenta-juan`, `cuenta-maria`, `cuenta-externa` +2. **Documenta la configuración:** Crea un archivo `INSTANCIAS.txt` con la asignación +3. **Automatiza con scripts:** Crea scripts para iniciar/detener todo de una vez +4. **Monitorea recursos:** Con varias instancias, monitorea CPU y memoria + +## 📝 Script de Inicialización (Opcional) + +Crea un archivo `init-multi-instances.ps1`: + +```powershell +param( + [int]$NumInstances = 3 +) + +for ($i = 1; $i -le $NumInstances; $i++) { + $instanceName = "instancia$i" + $port = 8088 + $i + + Write-Host "Creando $instanceName en puerto $port..." -ForegroundColor Green + + mkdir -Force "$instanceName/engine", "$instanceName/cron" + Copy-Item -Path "docker-compose.yml", ".env.example" -Destination "$instanceName" + Copy-Item -Path "engine\*" -Destination "$instanceName\engine" -Recurse -Force + Copy-Item -Path "cron\*" -Destination "$instanceName\cron" -Recurse -Force + + # Crear .env + @" +COMPOSE_PROJECT_NAME=$instanceName +ENGINE_PORT=$port +E5_CLIENT_ID=cambiar_aqui +E5_CLIENT_SECRET=cambiar_aqui +E5_REFRESH_TOKEN=cambiar_aqui +WEB_APP_PASSWORD=cambiar_aqui +E5_WEB_APP_PASSWORD=cambiar_aqui +CRON_PASSWORD=cambiar_aqui +CRON_REFRESH_TOKEN=cambiar_aqui +"@ | Set-Content "$instanceName\.env" + + Write-Host "$instanceName creada. Edita $instanceName\.env con tus credenciales" -ForegroundColor Yellow +} +``` + +Uso: + +```powershell +.\init-multi-instances.ps1 -NumInstances 3 +``` diff --git a/README.md b/README.md index 11ea808..4528eca 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ Sistema automatizado para la renovación de Microsoft E5 usando Docker, compuesto por dos servicios principales que trabajan en conjunto. +> **✨ Nueva Característica:** Este proyecto ahora soporta ejecutar **múltiples instancias** en la misma máquina sin conflictos de puertos. [Ver documentación →](MULTI_INSTANCIAS.md) + ## 📋 Descripción Este proyecto implementa un sistema de dos contenedores Docker: @@ -9,17 +11,14 @@ Este proyecto implementa un sistema de dos contenedores Docker: - **odengin**: Motor principal que gestiona la renovación automática de Microsoft E5 - **odcron**: Servicio de tareas programadas que se comunica con el motor principal -## 🏗️ Arquitectura +### Características -``` -┌─────────────────┐ ┌─────────────────┐ -│ odcron │────────>│ odengin │ -│ (Scheduler) │ HTTP │ (Engine) │ -│ Port: N/A │ │ Port: 8080 │ -└─────────────────┘ └─────────────────┘ -``` - -Los servicios se comunican a través de una red Docker privada (`odeng-net`). +✅ Soporte para múltiples instancias en la misma máquina +✅ Configuración con variables de entorno (`.env`) +✅ Redes Docker aisladas por instancia +✅ Health checks automáticos +✅ Reinicio automático de servicios +✅ Fácil de escalar y mantener ## 🚀 Inicio Rápido @@ -117,22 +116,41 @@ El archivo `.env.example` se incluye como referencia para documentar qué variab ### Puertos - **8089**: Puerto expuesto del servicio odengin (mapea al 8080 interno) +- Para múltiples instancias, usa puertos diferentes: 8089, 8090, 8091, etc. + +## 🚀 Múltiples Instancias + +Este proyecto está diseñado para ejecutar múltiples instancias en la misma máquina: + +```bash +# Instancia 1 - Puerto 8089 +COMPOSE_PROJECT_NAME=instancia1 ENGINE_PORT=8089 docker-compose up -d + +# Instancia 2 - Puerto 8090 +COMPOSE_PROJECT_NAME=instancia2 ENGINE_PORT=8090 docker-compose up -d + +# Instancia 3 - Puerto 8091 +COMPOSE_PROJECT_NAME=instancia3 ENGINE_PORT=8091 docker-compose up -d +``` + +**Ver documentación completa de múltiples instancias:** [MULTI_INSTANCIAS.md](MULTI_INSTANCIAS.md) ## 📁 Estructura del Proyecto ``` onedrive/ -├── docker-compose.yml # Orquestación de servicios +├── docker-compose.yml # Orquestación de servicios (multi-instancia) ├── README.md # Este archivo +├── MULTI_INSTANCIAS.md # Guía para ejecutar múltiples instancias +├── .env.example # Plantilla de configuración +├── .gitignore # Archivos a ignorar ├── cron/ # Servicio de tareas programadas │ ├── Dockerfile -│ ├── docker-compose.yml │ ├── requirements.txt │ ├── script.py │ └── README.md └── engine/ # Motor principal ├── Dockerfile - ├── docker-compose.yml └── README.md ``` diff --git a/docker-compose.yml b/docker-compose.yml index 25b82ab..8c81668 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,8 +1,11 @@ --- +# Multi-instance compatible Docker Compose configuration +# Para ejecutar múltiples instancias: docker-compose -f docker-compose.yml -p instancia1 up -d + services: odengin: build: ./engine - container_name: odengin + container_name: ${COMPOSE_PROJECT_NAME:-onedrive}-odengin env_file: .env environment: - E5_CLIENT_ID=${E5_CLIENT_ID} @@ -11,27 +14,34 @@ services: - WEB_APP_PASSWORD=${WEB_APP_PASSWORD} - E5_WEB_APP_PASSWORD=${E5_WEB_APP_PASSWORD} ports: - - "8089:8080" + - "${ENGINE_PORT:-8089}:8080" restart: unless-stopped - hostname: odengin + hostname: ${COMPOSE_PROJECT_NAME:-onedrive}-odengin networks: - - odeng-net + - ${COMPOSE_PROJECT_NAME:-onedrive}-net + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8080/health || exit 1"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s odcron: build: ./cron - container_name: odcron + container_name: ${COMPOSE_PROJECT_NAME:-onedrive}-odcron env_file: .env environment: - - IP=${CRON_IP:-odengin:8080} + - IP=${CRON_IP:-${COMPOSE_PROJECT_NAME:-onedrive}-odengin:8080} - PASSWORD=${CRON_PASSWORD} - REFRESH_TOKEN=${CRON_REFRESH_TOKEN} restart: unless-stopped - hostname: odcron + hostname: ${COMPOSE_PROJECT_NAME:-onedrive}-odcron networks: - - odeng-net + - ${COMPOSE_PROJECT_NAME:-onedrive}-net depends_on: - - odengin + odengin: + condition: service_healthy networks: - odeng-net: + ${COMPOSE_PROJECT_NAME:-onedrive}-net: driver: bridge