mirror of
https://github.com/turnstonelabs/turnstone.git
synced 2026-08-12 23:12:23 -06:00
d5db817391
Two runtime bugs: 1. Channel gateway advertised http://127.0.0.1:8091 which is unreachable from other Docker containers. Add TURNSTONE_CHANNEL_ADVERTISE_URL env var override for Docker/K8s environments, set to http://channel:8091 in compose.yaml, and pass --http-host=0.0.0.0 so the gateway listens on all interfaces. 2. Console proxy service JWT had only "write" scope but the approval endpoint requires "approve". Tool approval buttons in the server web UI silently failed when accessed through the console proxy. Changed proxy token scopes to read+write+approve.
275 lines
8.3 KiB
YAML
275 lines
8.3 KiB
YAML
# =============================================================================
|
|
# Turnstone Docker Compose Stack
|
|
#
|
|
# Usage:
|
|
# Default (SQLite): docker compose up
|
|
# Production (PG): DB_BACKEND=postgresql docker compose --profile production up
|
|
# (or set DB_BACKEND=postgresql in .env)
|
|
# With simulator: docker compose --profile sim up
|
|
# Scale bridges: docker compose up --scale bridge=3
|
|
# =============================================================================
|
|
|
|
name: turnstone
|
|
|
|
networks:
|
|
turnstone-net:
|
|
driver: bridge
|
|
|
|
volumes:
|
|
redis-data:
|
|
turnstone-data:
|
|
postgres-data:
|
|
|
|
services:
|
|
# -------------------------------------------------------------------
|
|
# PostgreSQL — production database (profile: production)
|
|
# -------------------------------------------------------------------
|
|
postgres:
|
|
image: postgres:17-alpine
|
|
profiles:
|
|
- production
|
|
environment:
|
|
POSTGRES_DB: turnstone
|
|
POSTGRES_USER: ${POSTGRES_USER:-turnstone}
|
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required for production profile}
|
|
volumes:
|
|
- postgres-data:/var/lib/postgresql/data
|
|
networks:
|
|
- turnstone-net
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-turnstone}"]
|
|
interval: 5s
|
|
timeout: 3s
|
|
retries: 5
|
|
start_period: 5s
|
|
deploy:
|
|
resources:
|
|
limits:
|
|
memory: 512M
|
|
cpus: '1.0'
|
|
restart: unless-stopped
|
|
|
|
# -------------------------------------------------------------------
|
|
# Redis — message broker, pub/sub, node registry
|
|
# -------------------------------------------------------------------
|
|
redis:
|
|
image: redis:7.4-alpine
|
|
command:
|
|
- sh
|
|
- -c
|
|
- >-
|
|
redis-server
|
|
--save 60 1
|
|
--loglevel warning
|
|
$${REDIS_PASSWORD:+--requirepass $$REDIS_PASSWORD}
|
|
ports:
|
|
- "${REDIS_PORT:-6379}:6379"
|
|
environment:
|
|
- REDIS_PASSWORD=${REDIS_PASSWORD:-}
|
|
volumes:
|
|
- redis-data:/data
|
|
networks:
|
|
- turnstone-net
|
|
healthcheck:
|
|
test:
|
|
- CMD-SHELL
|
|
- redis-cli $${REDIS_PASSWORD:+-a $$REDIS_PASSWORD} ping | grep -q PONG
|
|
interval: 5s
|
|
timeout: 3s
|
|
retries: 5
|
|
start_period: 5s
|
|
restart: unless-stopped
|
|
|
|
# -------------------------------------------------------------------
|
|
# turnstone-server — Web UI + chat workstreams + LLM interaction
|
|
# -------------------------------------------------------------------
|
|
server:
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile
|
|
command:
|
|
- sh
|
|
- -c
|
|
- >-
|
|
turnstone-server
|
|
--host 0.0.0.0
|
|
--port 8080
|
|
--base-url "$${LLM_BASE_URL}"
|
|
--api-key "$${OPENAI_API_KEY}"
|
|
$${MODEL:+--model $$MODEL}
|
|
$${SKIP_PERMISSIONS:+--skip-permissions}
|
|
ports:
|
|
- "${SERVER_PORT:-8080}:8080"
|
|
volumes:
|
|
- turnstone-data:/data
|
|
environment:
|
|
- LLM_BASE_URL=${LLM_BASE_URL:-http://host.docker.internal:8000/v1}
|
|
- OPENAI_API_KEY=${OPENAI_API_KEY:-dummy}
|
|
- TAVILY_API_KEY=${TAVILY_API_KEY:-}
|
|
- SKIP_PERMISSIONS=${SKIP_PERMISSIONS:-}
|
|
- TURNSTONE_AUTH_ENABLED=${TURNSTONE_AUTH_ENABLED:-}
|
|
- TURNSTONE_AUTH_TOKEN=${TURNSTONE_AUTH_TOKEN:-}
|
|
- TURNSTONE_JWT_SECRET=${TURNSTONE_JWT_SECRET:-}
|
|
- MODEL=${MODEL:-}
|
|
- TURNSTONE_DB_BACKEND=${DB_BACKEND:-sqlite}
|
|
- TURNSTONE_DB_URL=${DATABASE_URL:-}
|
|
- TURNSTONE_NODE_ID=${TURNSTONE_NODE_ID:-}
|
|
extra_hosts:
|
|
- "host.docker.internal:host-gateway"
|
|
networks:
|
|
- turnstone-net
|
|
depends_on:
|
|
redis:
|
|
condition: service_healthy
|
|
postgres:
|
|
condition: service_healthy
|
|
required: false
|
|
healthcheck:
|
|
test: ["CMD", "python", "/usr/local/bin/healthcheck.py", "http://127.0.0.1:8080/health"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 3
|
|
start_period: 15s
|
|
restart: unless-stopped
|
|
|
|
# -------------------------------------------------------------------
|
|
# turnstone-bridge — Redis <-> HTTP bridge for multi-node routing
|
|
# Node ID auto-generated from container hostname (no --node-id needed)
|
|
# -------------------------------------------------------------------
|
|
bridge:
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile
|
|
command:
|
|
- turnstone-bridge
|
|
- --server-url=http://server:8080
|
|
- --redis-host=redis
|
|
- --redis-port=6379
|
|
- --heartbeat-ttl=${HEARTBEAT_TTL:-60}
|
|
- --approval-timeout=${APPROVAL_TIMEOUT:-3600}
|
|
environment:
|
|
- REDIS_PASSWORD=${REDIS_PASSWORD:-}
|
|
- TURNSTONE_AUTH_TOKEN=${TURNSTONE_AUTH_TOKEN:-}
|
|
- TURNSTONE_JWT_SECRET=${TURNSTONE_JWT_SECRET:-}
|
|
networks:
|
|
- turnstone-net
|
|
depends_on:
|
|
server:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_healthy
|
|
restart: unless-stopped
|
|
|
|
# -------------------------------------------------------------------
|
|
# turnstone-console — Cluster dashboard
|
|
# -------------------------------------------------------------------
|
|
console:
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile
|
|
command:
|
|
- turnstone-console
|
|
- --host=0.0.0.0
|
|
- --port=8090
|
|
- --redis-host=redis
|
|
- --redis-port=6379
|
|
- --poll-interval=${CONSOLE_POLL_INTERVAL:-10}
|
|
ports:
|
|
- "${CONSOLE_PORT:-8090}:8090"
|
|
environment:
|
|
- REDIS_PASSWORD=${REDIS_PASSWORD:-}
|
|
- TURNSTONE_AUTH_ENABLED=${TURNSTONE_AUTH_ENABLED:-}
|
|
- TURNSTONE_AUTH_TOKEN=${TURNSTONE_AUTH_TOKEN:-}
|
|
- TURNSTONE_JWT_SECRET=${TURNSTONE_JWT_SECRET:-}
|
|
- TURNSTONE_DB_BACKEND=${DB_BACKEND:-sqlite}
|
|
- TURNSTONE_DB_URL=${DATABASE_URL:-}
|
|
networks:
|
|
- turnstone-net
|
|
depends_on:
|
|
redis:
|
|
condition: service_healthy
|
|
healthcheck:
|
|
test: ["CMD", "python", "/usr/local/bin/healthcheck.py", "http://127.0.0.1:8090/health"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 3
|
|
start_period: 10s
|
|
restart: unless-stopped
|
|
|
|
# -------------------------------------------------------------------
|
|
# turnstone-channel — Channel gateway (Discord, Slack, etc.)
|
|
# Requires TURNSTONE_DISCORD_TOKEN to enable Discord adapter
|
|
# -------------------------------------------------------------------
|
|
channel:
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile
|
|
profiles:
|
|
- production
|
|
command:
|
|
- sh
|
|
- -c
|
|
- >-
|
|
turnstone-channel
|
|
--redis-host=redis
|
|
--redis-port=6379
|
|
--http-host=0.0.0.0
|
|
$${TURNSTONE_DISCORD_GUILD:+--discord-guild $$TURNSTONE_DISCORD_GUILD}
|
|
environment:
|
|
- TURNSTONE_DISCORD_TOKEN=${TURNSTONE_DISCORD_TOKEN:-}
|
|
- TURNSTONE_DISCORD_GUILD=${TURNSTONE_DISCORD_GUILD:-0}
|
|
- REDIS_PASSWORD=${REDIS_PASSWORD:-}
|
|
- TURNSTONE_JWT_SECRET=${TURNSTONE_JWT_SECRET:-}
|
|
- TURNSTONE_DB_BACKEND=${DB_BACKEND:-sqlite}
|
|
- TURNSTONE_DB_URL=${DATABASE_URL:-}
|
|
- TURNSTONE_CHANNEL_ADVERTISE_URL=http://channel:8091
|
|
networks:
|
|
- turnstone-net
|
|
depends_on:
|
|
redis:
|
|
condition: service_healthy
|
|
postgres:
|
|
condition: service_healthy
|
|
required: false
|
|
restart: unless-stopped
|
|
|
|
# -------------------------------------------------------------------
|
|
# turnstone-sim — Multi-node cluster simulator (no LLM needed)
|
|
# Start with: docker compose --profile sim up
|
|
# -------------------------------------------------------------------
|
|
sim:
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile
|
|
profiles:
|
|
- sim
|
|
command:
|
|
- sh
|
|
- -c
|
|
- >-
|
|
turnstone-sim
|
|
--nodes "$${SIM_NODES}"
|
|
--scenario "$${SIM_SCENARIO}"
|
|
--duration "$${SIM_DURATION}"
|
|
--mps "$${SIM_MPS}"
|
|
--redis-host redis
|
|
--redis-port 6379
|
|
--log-level "$${SIM_LOG_LEVEL}"
|
|
$${SIM_SEED:+--seed $$SIM_SEED}
|
|
$${SIM_METRICS_FILE:+--metrics-file $$SIM_METRICS_FILE}
|
|
environment:
|
|
- REDIS_PASSWORD=${REDIS_PASSWORD:-}
|
|
- SIM_NODES=${SIM_NODES:-100}
|
|
- SIM_SCENARIO=${SIM_SCENARIO:-steady}
|
|
- SIM_DURATION=${SIM_DURATION:-60}
|
|
- SIM_MPS=${SIM_MPS:-5.0}
|
|
- SIM_LOG_LEVEL=${SIM_LOG_LEVEL:-INFO}
|
|
- SIM_SEED=${SIM_SEED:-}
|
|
- SIM_METRICS_FILE=${SIM_METRICS_FILE:-}
|
|
networks:
|
|
- turnstone-net
|
|
depends_on:
|
|
redis:
|
|
condition: service_healthy
|
|
restart: "no"
|