From 758b7bb39cc7fef901e9dc4c20c1e45b687564b6 Mon Sep 17 00:00:00 2001 From: devRaGonSa Date: Thu, 4 Jun 2026 09:24:09 +0200 Subject: [PATCH] chore: add JTA docker compose deployment --- deploy/jta/.env.example | 25 ++++++ deploy/jta/README.md | 164 ++++++++++++++++++++++++++++++++++ deploy/jta/backups/.gitkeep | 1 + deploy/jta/docker-compose.yml | 140 +++++++++++++++++++++++++++++ 4 files changed, 330 insertions(+) create mode 100644 deploy/jta/.env.example create mode 100644 deploy/jta/README.md create mode 100644 deploy/jta/backups/.gitkeep create mode 100644 deploy/jta/docker-compose.yml diff --git a/deploy/jta/.env.example b/deploy/jta/.env.example new file mode 100644 index 0000000..42d7fab --- /dev/null +++ b/deploy/jta/.env.example @@ -0,0 +1,25 @@ +POSTGRES_DB=hll_vietnam +POSTGRES_USER=hll_vietnam +POSTGRES_PASSWORD=change-me +POSTGRES_PORT=5432 + +BACKEND_PORT=8000 +FRONTEND_PORT=8080 +FRONTEND_BACKEND_BASE_URL=http://127.0.0.1:8000 +HLL_BACKEND_ALLOWED_ORIGINS=http://127.0.0.1:8080,http://localhost:8080 + +HLL_BACKEND_DATABASE_URL=postgresql://hll_vietnam:change-me@postgres:5432/hll_vietnam +HLL_BACKEND_LIVE_DATA_SOURCE=rcon +HLL_BACKEND_HISTORICAL_DATA_SOURCE=rcon +HLL_BACKEND_RCON_TARGETS='[{"name":"Comunidad Hispana #01","slug":"comunidad-hispana-01","external_server_id":"comunidad-hispana-01","host":"203.0.113.10","port":7779,"password":"replace-me-01","source_name":"community-hispana-rcon","region":"ES","game_port":7777,"query_port":7778}]' + +HLL_DB_MAINTENANCE_ENABLED=false +HLL_DB_MAINTENANCE_INTERVAL_SECONDS=43200 +HLL_RECENT_MATCHES_KEEP=100 +HLL_ADMIN_LOG_NONCRITICAL_RETENTION_DAYS=30 +HLL_ADMIN_LOG_CRITICAL_RETENTION_DAYS=90 +HLL_SERVER_SNAPSHOT_RETENTION_DAYS=14 +HLL_DB_MAINTENANCE_BATCH_SIZE=5000 + +HLL_BACKEND_RCON_HISTORICAL_INTERVAL_SECONDS=600 +HLL_BACKEND_RCON_ADMIN_LOG_LOOKBACK_MINUTES=10 diff --git a/deploy/jta/README.md b/deploy/jta/README.md new file mode 100644 index 0000000..8008391 --- /dev/null +++ b/deploy/jta/README.md @@ -0,0 +1,164 @@ +# JTA Docker Compose Deploy + +Este despliegue prepara una variante directa para JTA sin Portainer y sin tocar +la logica funcional del proyecto. + +## Archivos + +- `docker-compose.yml`: stack directo para JTA +- `.env.example`: plantilla de variables sin credenciales reales +- `backups/`: carpeta local para dumps `.dump` o `.sql` + +## Preparacion + +1. Copia la plantilla: + + ```powershell + Copy-Item deploy/jta/.env.example deploy/jta/.env + ``` + +2. Ajusta como minimo: + +- `POSTGRES_PASSWORD` +- `HLL_BACKEND_RCON_TARGETS` +- `FRONTEND_BACKEND_BASE_URL` +- `HLL_BACKEND_ALLOWED_ORIGINS` + +Notas: + +- `HLL_BACKEND_RCON_TARGETS` debe ser un JSON valido en una sola linea. +- en `.env` conviene dejar ese JSON entre comillas simples para preservar los espacios +- `HLL_DB_MAINTENANCE_ENABLED=false` queda desactivado por defecto. +- `FRONTEND_BACKEND_BASE_URL` debe apuntar a la URL que vera el navegador. + Ejemplo remoto: `http://IP_O_DOMINIO_JTA:8000`. +- `HLL_BACKEND_ALLOWED_ORIGINS` debe incluir la URL publica del frontend. + Ejemplo remoto: `http://IP_O_DOMINIO_JTA:8080`. + +## Arranque + +Desde la raiz del repo: + +```powershell +docker compose -f deploy/jta/docker-compose.yml --env-file deploy/jta/.env up -d --build +``` + +Alternativa equivalente desde `deploy/jta`: + +```powershell +cd deploy/jta +docker compose --env-file .env up -d --build +``` + +Ambas funcionan porque los contextos de build y los bind mounts se resuelven +relativos a `deploy/jta/docker-compose.yml`. + +## Arranque Con Workers Advanced + +Desde raiz: + +```powershell +docker compose -f deploy/jta/docker-compose.yml --env-file deploy/jta/.env --profile advanced up -d --build +``` + +Desde `deploy/jta`: + +```powershell +docker compose --env-file .env --profile advanced up -d --build +``` + +Servicios: + +- normales: `postgres`, `backend`, `frontend` +- perfil `advanced`: `historical-runner`, `rcon-historical-worker` + +## Parada + +Parada sin borrar datos: + +```powershell +docker compose -f deploy/jta/docker-compose.yml --env-file deploy/jta/.env down +``` + +Advertencia: + +- no usar `docker compose down -v` +- no borrar el volumen `jta-postgres-data` + +## Backup Y Restore + +Esta task no ejecuta backup ni restore real. Los comandos siguientes son solo +runbook operativo. + +### 1. Crear dump desde el PostgreSQL actual + +Ejemplo usando el contenedor PostgreSQL actual: + +```powershell +docker exec -t hll-vietnam-postgres pg_dump -U hll_vietnam -d hll_vietnam -Fc -f /tmp/hll_vietnam_jta.dump +docker cp hll-vietnam-postgres:/tmp/hll_vietnam_jta.dump .\hll_vietnam_jta.dump +Copy-Item .\hll_vietnam_jta.dump deploy\jta\backups\ +``` + +Si el nombre del contenedor actual es distinto, sustituirlo por el real. + +### 2. Levantar solo PostgreSQL en JTA + +```powershell +docker compose -f deploy/jta/docker-compose.yml --env-file deploy/jta/.env up -d postgres +``` + +### 3. Restaurar dump en JTA + +Con el dump ya copiado a `deploy/jta/backups/`: + +```powershell +docker compose -f deploy/jta/docker-compose.yml --env-file deploy/jta/.env exec postgres sh -c "pg_restore --clean --if-exists -U \"$POSTGRES_USER\" -d \"$POSTGRES_DB\" /backups/hll_vietnam_jta.dump" +``` + +## Validacion De Datos Tras Restore + +Comprobar tablas clave: + +```powershell +docker compose -f deploy/jta/docker-compose.yml --env-file deploy/jta/.env exec postgres sh -c "psql -U \"$POSTGRES_USER\" -d \"$POSTGRES_DB\" -c 'select count(*) from rcon_materialized_matches;'" +docker compose -f deploy/jta/docker-compose.yml --env-file deploy/jta/.env exec postgres sh -c "psql -U \"$POSTGRES_USER\" -d \"$POSTGRES_DB\" -c 'select count(*) from rcon_admin_log_events;'" +docker compose -f deploy/jta/docker-compose.yml --env-file deploy/jta/.env exec postgres sh -c "psql -U \"$POSTGRES_USER\" -d \"$POSTGRES_DB\" -c 'select count(*) from displayed_historical_snapshots;'" +``` + +## Endpoints A Probar + +- frontend: `http://IP_O_DOMINIO_JTA:8080` +- backend health: `http://IP_O_DOMINIO_JTA:8000/health` +- `http://IP_O_DOMINIO_JTA:8000/api/servers` +- `http://IP_O_DOMINIO_JTA:8000/api/historical/server-summary?server=comunidad-hispana-01` +- `http://IP_O_DOMINIO_JTA:8000/api/historical/recent-matches?limit=20&server=comunidad-hispana-01` + +## Logs A Revisar + +Basicos: + +```powershell +docker compose -f deploy/jta/docker-compose.yml --env-file deploy/jta/.env logs --tail=200 postgres backend frontend +``` + +Advanced: + +```powershell +docker compose -f deploy/jta/docker-compose.yml --env-file deploy/jta/.env logs --tail=200 historical-runner rcon-historical-worker +``` + +Eventos utiles a buscar: + +- `database-maintenance-scheduler-*` +- `historical-refresh-*` +- `database-maintenance-*` +- errores de conexion RCON + +## Validacion Del Compose + +La plantilla incluida usa valores de ejemplo sintacticamente validos, incluido +el JSON de `HLL_BACKEND_RCON_TARGETS`, para permitir: + +```powershell +docker compose -f deploy/jta/docker-compose.yml --env-file deploy/jta/.env.example config +``` diff --git a/deploy/jta/backups/.gitkeep b/deploy/jta/backups/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/deploy/jta/backups/.gitkeep @@ -0,0 +1 @@ + diff --git a/deploy/jta/docker-compose.yml b/deploy/jta/docker-compose.yml new file mode 100644 index 0000000..09fa43c --- /dev/null +++ b/deploy/jta/docker-compose.yml @@ -0,0 +1,140 @@ +services: + postgres: + image: postgres:16-alpine + command: + - postgres + - -p + - ${POSTGRES_PORT:-5432} + environment: + POSTGRES_DB: ${POSTGRES_DB:-hll_vietnam} + POSTGRES_USER: ${POSTGRES_USER:-hll_vietnam} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-change-me} + POSTGRES_PORT: ${POSTGRES_PORT:-5432} + TZ: Europe/Madrid + ports: + - "${POSTGRES_PORT:-5432}:${POSTGRES_PORT:-5432}" + volumes: + - jta-postgres-data:/var/lib/postgresql/data + - ./backups:/backups + healthcheck: + test: + - CMD-SHELL + - pg_isready -U "$$POSTGRES_USER" -d "$$POSTGRES_DB" -p "$$POSTGRES_PORT" + interval: 10s + timeout: 5s + retries: 12 + restart: unless-stopped + + backend: + image: hll-vietnam-backend:jta + build: + context: ../../backend + dockerfile: Dockerfile + environment: &backend_environment + HLL_BACKEND_HOST: 0.0.0.0 + HLL_BACKEND_PORT: ${BACKEND_PORT:-8000} + HLL_BACKEND_DATABASE_URL: ${HLL_BACKEND_DATABASE_URL:?HLL_BACKEND_DATABASE_URL is required} + HLL_BACKEND_ALLOWED_ORIGINS: ${HLL_BACKEND_ALLOWED_ORIGINS:?HLL_BACKEND_ALLOWED_ORIGINS is required} + HLL_BACKEND_LIVE_DATA_SOURCE: ${HLL_BACKEND_LIVE_DATA_SOURCE:-rcon} + HLL_BACKEND_HISTORICAL_DATA_SOURCE: ${HLL_BACKEND_HISTORICAL_DATA_SOURCE:-rcon} + HLL_BACKEND_RCON_TARGETS: ${HLL_BACKEND_RCON_TARGETS:?HLL_BACKEND_RCON_TARGETS is required} + HLL_DB_MAINTENANCE_ENABLED: ${HLL_DB_MAINTENANCE_ENABLED:-false} + HLL_DB_MAINTENANCE_INTERVAL_SECONDS: ${HLL_DB_MAINTENANCE_INTERVAL_SECONDS:-43200} + HLL_RECENT_MATCHES_KEEP: ${HLL_RECENT_MATCHES_KEEP:-100} + HLL_ADMIN_LOG_NONCRITICAL_RETENTION_DAYS: ${HLL_ADMIN_LOG_NONCRITICAL_RETENTION_DAYS:-30} + HLL_ADMIN_LOG_CRITICAL_RETENTION_DAYS: ${HLL_ADMIN_LOG_CRITICAL_RETENTION_DAYS:-90} + HLL_SERVER_SNAPSHOT_RETENTION_DAYS: ${HLL_SERVER_SNAPSHOT_RETENTION_DAYS:-14} + HLL_DB_MAINTENANCE_BATCH_SIZE: ${HLL_DB_MAINTENANCE_BATCH_SIZE:-5000} + ports: + - "${BACKEND_PORT:-8000}:${BACKEND_PORT:-8000}" + depends_on: + postgres: + condition: service_healthy + volumes: + - jta-backend-data:/app/data + restart: unless-stopped + + frontend: + build: + context: ../../frontend + dockerfile: Dockerfile + command: + - sh + - -c + - | + python - <<'PY' + import os + import re + from pathlib import Path + + base_url = os.environ.get("FRONTEND_BACKEND_BASE_URL", "http://127.0.0.1:8000") + pattern = re.compile(r'data-backend-base-url="[^"]*"') + replacement = f'data-backend-base-url="{base_url}"' + + for path in Path("/srv/frontend").glob("*.html"): + text = path.read_text(encoding="utf-8") + text = pattern.sub(replacement, text) + path.write_text(text, encoding="utf-8") + PY + python -m http.server "${FRONTEND_PORT:-8080}" --bind 0.0.0.0 --directory /srv/frontend + environment: + FRONTEND_PORT: ${FRONTEND_PORT:-8080} + FRONTEND_BACKEND_BASE_URL: ${FRONTEND_BACKEND_BASE_URL:?FRONTEND_BACKEND_BASE_URL is required} + ports: + - "${FRONTEND_PORT:-8080}:${FRONTEND_PORT:-8080}" + depends_on: + backend: + condition: service_started + restart: unless-stopped + + historical-runner: + profiles: + - advanced + image: hll-vietnam-backend:jta + build: + context: ../../backend + dockerfile: Dockerfile + command: + - python + - -m + - app.historical_runner + - --hourly + environment: + <<: *backend_environment + depends_on: + postgres: + condition: service_healthy + backend: + condition: service_started + volumes: + - jta-backend-data:/app/data + restart: unless-stopped + + rcon-historical-worker: + profiles: + - advanced + image: hll-vietnam-backend:jta + build: + context: ../../backend + dockerfile: Dockerfile + command: + - python + - -m + - app.rcon_historical_worker + - loop + environment: + <<: *backend_environment + HLL_RCON_HISTORICAL_CAPTURE_INTERVAL_SECONDS: ${HLL_BACKEND_RCON_HISTORICAL_INTERVAL_SECONDS:-600} + HLL_BACKEND_RCON_ADMIN_LOG_LOOKBACK_MINUTES: ${HLL_BACKEND_RCON_ADMIN_LOG_LOOKBACK_MINUTES:-10} + depends_on: + postgres: + condition: service_healthy + backend: + condition: service_started + volumes: + - jta-backend-data:/app/data + restart: unless-stopped + +volumes: + jta-postgres-data: + jta-backend-data: