R2D2-Holocron/docker-compose.yml
Joshua Belke 88ffa3cad5
Some checks failed
Holocron Frontend CI / lint-and-test (push) Has been cancelled
refactor(compose): unify into single file with local/dev/demo profiles
K8s is the production target — docker compose is local-only. Collapse the
three compose files (docker-compose.yml, .local.yml, .local-dev.yml) into a
single docker-compose.yml driven by profiles:

  local  → full stack in containers
  dev    → backing services only; frontend on host (npm run start:dev)
  demo   → synthetic MQTT publisher (composable with local or dev)

Make targets:
  make up      → --profile local --profile demo
  make up-dev  → --profile dev   --profile demo
  make up-bare → --profile local (no synthetic data)

All values (MQTT_TOPIC_PREFIX, MAPTILER_KEY, KEYCLOAK_*, host port mappings)
are env-driven with sensible local defaults. The same env contract is what
the K8s ConfigMap will inject in production.

Also:
- Bump frontend Dockerfile (local/dev) from node:18 → node:20-alpine.
  Vite 7 requires crypto.hash (Node 20.12+). Also bumps the test-publisher
  base image to node:20-alpine.
- Default host MQTT port moved to 1885 and frontend to 3002 (compose env
  defaults) to avoid common conflicts; both overridable via .env.

Verified:
- docker compose --profile local --profile demo config parses OK
- docker compose --profile dev   --profile demo config parses OK
- `make up` brings up 6 healthy containers
- curl localhost:7070/health → 200
- curl localhost:3002 → 200
- Test publisher streams UAV/SHIP/HELO/TANK positions on r2d2/holocron/...
- Browser screenshot confirms Cesium map rendering with live MQTT assets

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 09:57:46 -04:00

158 lines
5.1 KiB
YAML

---
# Unified docker-compose for R2D2-Holocron.
#
# Profiles:
# local → full stack in containers (frontend served by Node from image)
# dev → backing services only; run frontend on host with `npm run start:dev`
# (proxy is configured to forward to host.docker.internal)
# demo → adds test-publisher streaming synthetic MQTT assets
#
# Production deploys to Kubernetes (not this file). The env contract below
# (MQTT_TOPIC_PREFIX, MAPTILER_KEY, KEYCLOAK_*, etc.) is the same contract the
# K8s manifests will inject via ConfigMap/Secret. Keep it stable.
#
# Usage:
# make up # local + demo (default)
# make up-dev # dev + demo
# docker compose --profile local up -d # local only (no test publisher)
# docker compose --profile dev up -d # dev only
#
# Endpoints (local profile):
# - Proxy: http://localhost:${PROXY_PORT:-7070}
# - Health: http://localhost:${PROXY_PORT:-7070}/health
# - Keycloak: http://localhost:${PROXY_PORT:-7070}/auth
# - Frontend: http://localhost:${FRONTEND_PORT:-3002}
# - WebSocket: ws://localhost:${WS_PORT:-9002}
# - MQTT: tcp://localhost:${MQTT_PORT:-1885}
services:
holocron-keycloak-postgresql:
profiles: [local, dev]
image: postgres:15-alpine
container_name: holocron-keycloak-postgresql-local
restart: unless-stopped
volumes:
- keycloak_postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_DB: ${KEYCLOAK_DB_NAME:-keycloak_db}
POSTGRES_USER: ${KEYCLOAK_DB_USER:-keycloakuser}
POSTGRES_PASSWORD: ${KEYCLOAK_DB_PASSWORD:-keycloakuser}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${KEYCLOAK_DB_USER:-keycloakuser} -d ${KEYCLOAK_DB_NAME:-keycloak_db}"]
interval: 15s
timeout: 15s
retries: 5
holocron-keycloak:
profiles: [local, dev]
build:
context: ./holocron-keycloak
dockerfile: Dockerfile.local.public
image: holocron-keycloak:local
container_name: holocron-keycloak-local
restart: unless-stopped
command:
[
"-Dkeycloak.migration.action=import",
"-Dkeycloak.migration.provider=dir",
"-Dkeycloak.migration.dir=/opt/keycloak/data/import",
"-Dkeycloak.migration.strategy=IGNORE_EXISTING"
]
environment:
KC_DB_URL: jdbc:postgresql://holocron-keycloak-postgresql-local/${KEYCLOAK_DB_NAME:-keycloak_db}
KC_DB_USERNAME: ${KEYCLOAK_DB_USER:-keycloakuser}
KC_DB_PASSWORD: ${KEYCLOAK_DB_PASSWORD:-keycloakuser}
KEYCLOAK_ADMIN: ${KEYCLOAK_ADMIN:-adminkeycloak}
KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD:-adminkeycloak}
KC_HTTP_PORT: 8090
depends_on:
holocron-keycloak-postgresql:
condition: service_healthy
holocron-proxy:
profiles: [local]
build:
context: ./holocron-proxy
dockerfile: Dockerfile.local.public
image: holocron-proxy:local
container_name: holocron-proxy-local
restart: unless-stopped
ports:
- "${PROXY_PORT:-7070}:7070"
depends_on:
- holocron-keycloak
holocron-proxy-dev:
profiles: [dev]
build:
context: ./holocron-proxy
dockerfile: Dockerfile.local.public
image: holocron-proxy:local
container_name: holocron-proxy-local
restart: unless-stopped
ports:
- "${PROXY_PORT:-7070}:7070"
volumes:
- ./holocron-proxy/nginx/local-dev.conf:/etc/nginx/conf.d/default.conf
extra_hosts:
- "host.docker.internal:host-gateway"
depends_on:
- holocron-keycloak
mosquitto:
profiles: [local, dev]
image: eclipse-mosquitto:2
container_name: holocron-mosquitto-local
restart: unless-stopped
ports:
- "${MQTT_PORT:-1885}:1883"
- "${MQTT_WS_PORT:-9001}:9001"
volumes:
- ./mosquitto/config:/mosquitto/config
- mosquitto_data:/mosquitto/data
- mosquitto_log:/mosquitto/log
holocron-frontend:
profiles: [local]
build:
context: ./holocron-frontend
dockerfile: Dockerfile.local
image: holocron-frontend:local
container_name: holocron-frontend-local
restart: unless-stopped
env_file:
- .env
ports:
- "${FRONTEND_PORT:-3002}:3001"
- "${WS_PORT:-9002}:9002"
environment:
- NODE_ENV=production
- PORT=3001
- WS_PORT=9002
- MQTT_BROKER=mqtt://mosquitto:1883
- MQTT_TOPIC_PREFIX=${MQTT_TOPIC_PREFIX:-r2d2/holocron}
- MAPTILER_KEY=${MAPTILER_KEY:-}
depends_on:
- mosquitto
# Synthetic asset publisher (UAVs, ships, helos, tanks moving across Europe).
# Useful for both `local` and `dev` profiles when no real MQTT feed is wired up.
test-publisher:
profiles: [demo]
image: node:20-alpine
container_name: holocron-test-publisher-local
working_dir: /app
volumes:
- ./holocron-cesium/test-publisher:/app
command: sh -c "npm install && node publisher.js"
environment:
MQTT_BROKER: mqtt://mosquitto:1883
MQTT_TOPIC_PREFIX: ${MQTT_TOPIC_PREFIX:-r2d2/holocron}
depends_on:
- mosquitto
restart: unless-stopped
volumes:
keycloak_postgres_data:
mosquitto_data:
mosquitto_log: