didi-lot1-ai/ai_platform/modules/didi_brain/infra/docker-compose.yml

186 lines
7.4 KiB
YAML

# =============================================================================
# DidiBrain — Atomic + Postgres pgvector
# =============================================================================
# This compose stack runs four services:
# - postgres (pgvector/pgvector:pg16) on port 5434
# - atomic-server (kenforthewin/atomic-server:latest) on port 8088 (8080 internal)
# - brain-api (FastAPI service) on port 8090
# - scheduler (feeder + auditor + watcher + heartbeat, no exposed port)
# All four attach to the external shared `didi-network`.
#
# Atomic is configured to use Postgres as the data backend (atoms, embeddings,
# tags, etc.) while keeping the SQLite registry for tokens & global settings
# in the local volume at /data.
#
# AI provider config (BGE-M3 endpoint, qwen3.5 router) is NOT set here —
# it lives in Atomic's settings table and is bootstrapped post-startup by
# `scripts/02_bootstrap_atomic.py` which calls PUT /api/settings.
# =============================================================================
services:
postgres:
image: pgvector/pgvector:pg16
container_name: didibrain-postgres
environment:
POSTGRES_USER: ${POSTGRES_USER:-atomic}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-atomic_dev_changeme}
POSTGRES_DB: ${POSTGRES_DB:-atomic}
ports:
- "${POSTGRES_PORT:-5434}:5432"
volumes:
- didibrain-pg-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-atomic} -d ${POSTGRES_DB:-atomic}"]
interval: 3s
timeout: 5s
retries: 10
start_period: 5s
networks:
- didi-network
restart: unless-stopped
atomic-server:
image: ghcr.io/kenforthewin/atomic-server:latest
container_name: didibrain-atomic
# Override the upstream image's hard-coded `--db-path` (legacy SQLite mode)
# so we can use the modern `--data-dir` + `--storage postgres` flow.
entrypoint: ["atomic-server", "--data-dir", "/data"]
command: ["serve", "--bind", "0.0.0.0", "--port", "8080"]
environment:
ATOMIC_STORAGE: postgres
ATOMIC_DATABASE_URL: postgres://${POSTGRES_USER:-atomic}:${POSTGRES_PASSWORD:-atomic_dev_changeme}@postgres:5432/${POSTGRES_DB:-atomic}
RUST_LOG: "atomic_core=info,atomic_server=info,warn"
# PUBLIC_URL is required for OAuth/MCP discovery — fine to leave empty
# for local dev (we'll set it on the real server).
PUBLIC_URL: ""
ports:
# 8080 is taken on this dev box (aria-frontend); use 8088 externally,
# the container itself still listens on 8080 internally.
- "8088:8080"
volumes:
- didibrain-atomic-data:/data
depends_on:
postgres:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 5s
timeout: 3s
retries: 10
start_period: 15s
networks:
- didi-network
restart: unless-stopped
# Atomic-server makes outbound HTTPS calls to the LLM router and BGE
# endpoint. Since those live on the host network (10.11.10.x and
# localhost:14011), Linux containers need to reach them. Two options:
# 1. Use host.docker.internal:14011 for the router (Docker Desktop
# maps this to the host on Win/Mac).
# 2. Use the actual host IP for 10.11.10.x targets (Docker Desktop
# routes through WSL2's NAT, so 10.x is reachable directly).
# We rely on (2) being true for the BGE endpoint and (1) for the LLM
# router. The bootstrap script will configure both.
extra_hosts:
- "host.docker.internal:host-gateway"
brain-api:
# DidiBrain's HTTP service (speaks Didi's web-module contract).
# Build context is the didibrain/ root one level up, so shared/ and
# extractor/ get COPY'd in by the Dockerfile.
build:
context: ..
dockerfile: brain_api/Dockerfile
image: didibrain-api:latest
container_name: didibrain-api
# Load the full host .env (single source of truth for endpoints),
# then override the atomic URL to use Docker's internal DNS. Everything
# else — BGE, LLM router, model names — stays exactly as on the host.
env_file:
- ../.env
environment:
# Inside the compose network, atomic-server is reachable by its
# service name on its internal port (8080), NOT the host-mapped 8088.
ATOMIC_URL: http://atomic-server:8080
# brain_api connects directly to postgres for the verification cache.
# Inside the network, postgres is at 'postgres:5432' (not 5434/localhost).
POSTGRES_HOST: postgres
POSTGRES_INTERNAL_PORT: "5432"
# AI platform dashboard — RuntimeConfigClient polls /api/config every 30s
# for live overrides on atom_* and log_level. Empty/unset = polling
# disabled (settings/constants used as-is).
DASHBOARD_URL: ${DASHBOARD_URL:-http://didiAI-dashboard:51300}
# OTel — traces to OTel Collector → Jaeger
OTEL_EXPORTER_OTLP_ENDPOINT: ${OTEL_EXPORTER_OTLP_ENDPOINT:-http://didi-otel-collector:4317}
OTEL_SERVICE_NAME: didibrain-api
volumes:
# Mount the host-seeded taxonomy map so background extraction (which
# instantiates TagResolver directly, bypassing the app lifespan
# refresh) can find canonical tag UUIDs.
- ../shared/_tag_ids.json:/app/shared/_tag_ids.json:ro
ports:
- "8090:8090"
depends_on:
postgres:
condition: service_healthy
atomic-server:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-fsS", "http://localhost:8090/health"]
interval: 10s
timeout: 5s
retries: 5
start_period: 20s
networks:
- didi-network
restart: unless-stopped
# BGE endpoint (10.11.10.15) and LLM router (10.11.10.17) live on the
# VPN-routed internal network. Docker Desktop on Windows routes these
# through WSL2's NAT just like the atomic-server container already does,
# so no special extra_hosts entries are needed for them.
scheduler:
# Phase C — feeder (RSS hourly), auditor (daily LLM audit), and breaking
# news watcher in a single container. Imports brain_api.* directly for
# DB access (same Postgres pool, separate process).
build:
context: ..
dockerfile: scheduler/Dockerfile
image: didibrain-scheduler:latest
container_name: didibrain-scheduler
env_file:
- ../.env
environment:
# Same as brain-api — keeps the auditor's DB connection consistent.
ATOMIC_URL: http://atomic-server:8080
POSTGRES_HOST: postgres
POSTGRES_INTERNAL_PORT: "5432"
# Default brain target uses Docker DNS to reach the brain-api service
# in this same compose stack. Override per environment if needed.
SCHED_BRAIN_API_URL: http://brain-api:8090
SCHED_LOG_LEVEL: INFO
depends_on:
postgres:
condition: service_healthy
brain-api:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL",
"test -f /tmp/scheduler.healthy && test \"$$(($$(date +%s) - $$(stat -c %Y /tmp/scheduler.healthy)))\" -lt 300"]
interval: 60s
timeout: 10s
retries: 3
start_period: 60s
networks:
- didi-network
restart: unless-stopped
volumes:
didibrain-pg-data:
name: didibrain-pg-data
didibrain-atomic-data:
name: didibrain-atomic-data
networks:
didi-network:
external: true # single shared network for all DIDI + AI platform stacks