# Compose with Docker named volumes (default). No VOLUME_LOCAL_PATH required. # Alternative: compose-dir-volumes.yaml uses host dirs (bind mounts). # # Default (mini): Qdrant + app only. No profile needed. # docker compose -p kairos-mcp up -d # Fullstack: add Valkey, Postgres, Keycloak (use with fullstack .env). # docker compose -p kairos-mcp --profile fullstack up -d # Optional UI (only with fullstack): docker compose -p kairos-mcp --profile fullstack --profile infra-ui up -d services: valkey: profiles: - fullstack image: valkey/valkey:8.1-alpine pull_policy: missing environment: KEY_VALUE_STORE_PASSWORD: ${KEY_VALUE_STORE_PASSWORD:-${REDIS_PASSWORD:-}} command: > sh -c 'if [ -z "$$KEY_VALUE_STORE_PASSWORD" ]; then echo "KEY_VALUE_STORE_PASSWORD (or REDIS_PASSWORD legacy alias) must be set when fullstack profile enables valkey" >&2; exit 1; fi; exec valkey-server --maxmemory 512mb --maxmemory-policy allkeys-lru --save 60 1000 --appendonly yes --requirepass "$$KEY_VALUE_STORE_PASSWORD"' ports: - "6379:6379" volumes: - valkey-data:/data networks: - kairos-network healthcheck: test: [ "CMD-SHELL", "valkey-cli -a \"$$KEY_VALUE_STORE_PASSWORD\" ping" ] interval: 10s timeout: 3s retries: 3 restart: unless-stopped # Optional UI for Valkey/Redis-compatible stores; use with fullstack. redisinsight: profiles: - infra-ui image: redis/redisinsight:3.2.0@sha256:55542a762210bb1cd681410282642bac0970f780f39bc134565394a81b1f1fd9 pull_policy: missing depends_on: - valkey ports: - "5540:5540" environment: - RI_REDIS_HOST*=valkey - RI_REDIS_PORT*=6379 - RI_REDIS_ALIAS*=kairosKeyValue volumes: - redisinsight-data:/data networks: - kairos-network restart: unless-stopped qdrant: image: qdrant/qdrant:v1.17.1@sha256:94728574965d17c6485dd361aa3c0818b325b9016dac5ea6afec7b4b2700865f pull_policy: missing ports: - "6333:6333" - "6344:6344" volumes: - qdrant-data:/qdrant/storage env_file: - .env environment: - QDRANT__SERVICE__HTTP_PORT=6333 - QDRANT__SERVICE__GRPC_PORT=6534 - QDRANT__SERVICE__API_KEY=${QDRANT_API_KEY:?QDRANT_API_KEY must be set} # Performance optimization for production - QDRANT__LOG_LEVEL=INFO - QDRANT__SERVICE__MAX_WORKING_MEMORY_MB=4096 networks: - kairos-network restart: unless-stopped # healthcheck: test: > fgrep -qa ':18BD ' /proc/net/tcp interval: 30s timeout: 5s retries: 3 # start_period: 3s # --- Postgres: Keycloak DB only (default Docker workflow via env). Regenerate: python3 scripts/deploy-generate-dev-secrets.py --ci --- postgres: profiles: - fullstack image: postgres:18.3-alpine3.22@sha256:50961b448dfcf6dcc2f1f73ec173edb60c1b9dd18245b3978a8a569e09d8b9aa env_file: - .env environment: POSTGRES_USER: keycloak POSTGRES_PASSWORD: ${KEYCLOAK_DB_PASSWORD:-} POSTGRES_DB: keycloak volumes: - postgres-data:/var/lib/postgresql/data ports: - "5432:5432" networks: - kairos-network healthcheck: test: ["CMD-SHELL", "pg_isready -U keycloak -d keycloak"] interval: 5s timeout: 5s retries: 10 restart: unless-stopped # --- Keycloak OIDC (see docs/plans/keycloak-oidc-dev.md). DB: postgres service, keycloak DB/user --- keycloak: profiles: - fullstack env_file: - .env image: quay.io/keycloak/keycloak:26.5.4@sha256:ae8efb0d218d8921334b03a2dbee7069a0b868240691c50a3ffc9f42fabba8b4 depends_on: postgres: condition: service_healthy # Idempotent realm setup via scripts/deploy-configure-keycloak-realms.py only (npm run infra:up). Do not add --import-realm. # Group mapper `full.path` is always applied by deploy-configure-keycloak-realms.py (not a Keycloak KC_* env var). command: - start-dev environment: KC_BOOTSTRAP_ADMIN_USERNAME: admin KC_BOOTSTRAP_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD:-} KC_DB: postgres KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak KC_DB_USERNAME: keycloak KC_DB_PASSWORD: ${KEYCLOAK_DB_PASSWORD:-} KC_HOSTNAME_STRICT: "false" KC_HTTP_ENABLED: "true" KC_HEALTH_ENABLED: "true" ports: - "8080:8080" - "9000:9000" # No bind mount: realm JSONs live in scripts/keycloak/import; use scripts/deploy-configure-keycloak-realms.py to create realms via API. networks: - kairos-network restart: unless-stopped app-prod: image: debian777/kairos-mcp:v4.4.0 #pull_policy: always labels: - "environment=prod" env_file: - .env ports: - "${PORT:-3000}:${PORT:-3000}" - "${METRICS_PORT:-9090}:${METRICS_PORT:-9090}" environment: # Container must reach Qdrant by service name - QDRANT_URL=http://qdrant:6333 - METRICS_PORT=${METRICS_PORT:-9090} # Snapshot backup dir (volume mount); omit to disable backup (503 on POST /api/snapshot) - QDRANT_SNAPSHOT_DIR=/snapshots # KEY_VALUE_STORE_URL/REDIS_URL and KEYCLOAK_INTERNAL_URL from .env (set for fullstack; omit for mini) volumes: - snapshots-prod:/snapshots depends_on: qdrant: condition: service_started networks: - kairos-network restart: unless-stopped # Health check covering both transports healthcheck: test: > wget --quiet --tries=1 --timeout=5 --spider http://127.0.0.1:$$PORT/health || exit 1 interval: 30s timeout: 5s retries: 3 start_period: 40s networks: kairos-network: driver: bridge volumes: valkey-data: redisinsight-data: qdrant-data: postgres-data: snapshots-prod: