Files
oikos/docker-compose.yml
dtoro 22fe1526ca
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
feat: add /deploy-plugins webhook route + deploy-plugins script
2026-08-17 00:05:55 +02:00

243 lines
8.5 KiB
YAML

# Docker Compose for Oikos development
# Usage: docker compose up -d postgres (just the DB)
# make dev (full dev stack)
#
# The control-room SPA lives in its own repo (dtoro/oikos-web) with its own
# compose project; the agent runtime (dsh) runs outside this stack and talks
# to api's /mcp like any MCP client.
services:
postgres:
image: timescale/timescaledb:2.17.2-pg16
restart: unless-stopped
environment:
POSTGRES_DB: oikos
POSTGRES_USER: oikos
POSTGRES_PASSWORD: ${OIKOS_DB_PASSWORD:-oikos_dev}
ports:
- "5432:5432"
volumes:
- pg-data:/var/lib/postgresql/data
mem_limit: 1g
cpus: 2.0
healthcheck:
test: ["CMD", "pg_isready", "-U", "oikos"]
interval: 5s
timeout: 5s
retries: 5
# One-shot: run migrations then exit
migrate:
image: oikos-migrate:${OIKOS_VERSION:-latest}
build:
context: .
dockerfile: compose/oikos/Dockerfile
depends_on:
postgres:
condition: service_healthy
environment:
OIKOS_DATABASE_URL: postgres://oikos:${OIKOS_DB_PASSWORD:-oikos_dev}@postgres:5432/oikos?sslmode=disable
command: ["migrate"]
restart: "no"
mem_limit: 512m
cpus: 1.0
# One-shot: ingest seeds then exit
seed:
image: oikos-seed:${OIKOS_VERSION:-latest}
build:
context: .
dockerfile: compose/oikos/Dockerfile
depends_on:
migrate:
condition: service_completed_successfully
environment:
OIKOS_DATABASE_URL: postgres://oikos:${OIKOS_DB_PASSWORD:-oikos_dev}@postgres:5432/oikos?sslmode=disable
OIKOS_SEEDS_DIR: /seeds
command: ["seed"]
restart: "no"
mem_limit: 512m
cpus: 1.0
# API server (Phase 2)
api:
image: oikos-api:${OIKOS_VERSION:-latest}
build:
context: .
dockerfile: compose/oikos/Dockerfile
restart: unless-stopped
profiles: ["dev", "full"]
depends_on:
seed:
condition: service_completed_successfully
environment:
OIKOS_DATABASE_URL: postgres://oikos:${OIKOS_DB_PASSWORD:-oikos_dev}@postgres:5432/oikos?sslmode=disable
OIKOS_API_LISTEN: ":8090"
OIKOS_ENV: dev
OIKOS_DEBUG: "true"
# No dev-open auth bypass (plans/2026-07-12-wails-desktop-app.md 0.4) —
# every request needs this token. dsh uses the same value to call
# into api's /mcp and /api/v1/approvals/*/decision.
OIKOS_MCP_BEARER_TOKEN: ${OIKOS_MCP_BEARER_TOKEN:-dev-token}
OIKOS_OIDC_ISSUER: ${OIKOS_OIDC_ISSUER:-https://auth.hubris.network/application/o/oikos/}
OIKOS_OIDC_CLIENT_ID: ${OIKOS_OIDC_CLIENT_ID:-otkHBSueHJsYtOHstL6rn5izeGgyOsavp1qA1hod}
OIKOS_NOMOS_AGENT_SLUG: ${OIKOS_NOMOS_AGENT_SLUG:-agent:nomos}
# Rate limiting (plan D3). Default off; set OIKOS_API_RATE_LIMIT to a
# requests/sec value to throttle runaway agent loops per source IP.
OIKOS_API_RATE_LIMIT: ${OIKOS_API_RATE_LIMIT:-}
OIKOS_API_RATE_BURST: ${OIKOS_API_RATE_BURST:-}
# Infisical secret store (Phase 5)
OIKOS_INFISICAL_SITE_URL: ${OIKOS_INFISICAL_SITE_URL:-}
OIKOS_INFISICAL_CLIENT_ID: ${OIKOS_INFISICAL_CLIENT_ID:-}
OIKOS_INFISICAL_CLIENT_SECRET: ${OIKOS_INFISICAL_CLIENT_SECRET:-}
OIKOS_INFISICAL_PROJECT_ID: ${OIKOS_INFISICAL_PROJECT_ID:-}
OIKOS_INFISICAL_ENV: ${OIKOS_INFISICAL_ENV:-dev}
volumes:
- ${OIKOS_SSH_KEY_PATH:-~/.ssh/id_ed25519}:/etc/oikos/ssh_key:ro
ports:
- "8090:8090"
command: ["api"]
stop_signal: SIGTERM
stop_grace_period: 30s
mem_limit: 512m
cpus: 1.0
# Self-probe so `docker compose ps` reports genuine readiness: /healthz
# pings the DB, so "healthy" means actually answering. wget is BusyBox's,
# already in the alpine runtime image, so this adds no dependency.
healthcheck:
test: ["CMD", "wget", "-q", "-O", "-", "http://127.0.0.1:8090/healthz"]
interval: 5s
timeout: 3s
retries: 10
# Migrations and seed run before this container, but the first bind can
# still take a moment; failures inside the start period don't count.
# The api's NewHandler stalls on TWO unreachable external deps at startup
# before binding :8090: Infisical (4x auth retries, ~40s) and OIDC
# discovery (auth.hubris.network, ~35s of timeouts). Total ~90-95s, so
# the start period must clear it.
start_period: 180s
# Scheduler (Phase 3) — observe loop
scheduler:
image: oikos-scheduler:${OIKOS_VERSION:-latest}
build:
context: .
dockerfile: compose/oikos/Dockerfile
restart: unless-stopped
profiles: ["dev", "full"]
depends_on:
seed:
condition: service_completed_successfully
environment:
OIKOS_DATABASE_URL: postgres://oikos:${OIKOS_DB_PASSWORD:-oikos_dev}@postgres:5432/oikos?sslmode=disable
OIKOS_DEBUG: "true"
OIKOS_SCHEDULER_INTERVAL: "30s"
OIKOS_SSH_KEY_PATH: /etc/oikos/ssh_key
OIKOS_SSH_USER: root
# Liveness probe (plan D5): exposes a staleness-aware /healthz inside
# the container; the scheduler bumps it each check pass.
OIKOS_HEALTH_LISTEN: ":8093"
volumes:
- ${OIKOS_SSH_KEY_PATH:-~/.ssh/id_ed25519}:/etc/oikos/ssh_key:ro
cap_add:
- NET_RAW
command: ["scheduler"]
stop_signal: SIGTERM
stop_grace_period: 30s
mem_limit: 256m
cpus: 1.0
healthcheck:
test: ["CMD", "wget", "-q", "-O", "-", "http://127.0.0.1:8093/healthz"]
interval: 30s
timeout: 5s
retries: 3
start_period: 90s
# Execution worker (Phase 6) — Postgres-backed job queue
execution-worker:
image: oikos-execution-worker:${OIKOS_VERSION:-latest}
build:
context: .
dockerfile: compose/oikos/Dockerfile
restart: unless-stopped
profiles: ["dev", "full"]
depends_on:
seed:
condition: service_completed_successfully
environment:
OIKOS_DATABASE_URL: postgres://oikos:${OIKOS_DB_PASSWORD:-oikos_dev}@postgres:5432/oikos?sslmode=disable
OIKOS_DEBUG: "true"
OIKOS_SSH_KEY_PATH: /etc/oikos/ssh_key
OIKOS_SSH_USER: root
OIKOS_HEALTH_LISTEN: ":8095"
volumes:
- ${OIKOS_SSH_KEY_PATH:-~/.ssh/id_ed25519}:/etc/oikos/ssh_key:ro
command: ["execution-worker"]
stop_signal: SIGTERM
stop_grace_period: 30s
mem_limit: 256m
cpus: 1.0
healthcheck:
test: ["CMD", "wget", "-q", "-O", "-", "http://127.0.0.1:8095/healthz"]
interval: 30s
timeout: 5s
retries: 3
start_period: 90s
# Nomos agent gateway (Phase 4) — decommissioned. Replaced by dsh
# (DeepSeek Harness) as the agent runtime; see
# plans/2026-08-16-dsh-as-agent-replace-nomos.md section 5. dsh runs
# outside this stack (Node.js sidecar, dev at http://127.0.0.1:3080)
# and talks to api's /mcp like any MCP client.
# The control-room SPA moved to its own repo (dtoro/oikos-web, Phase 1 of
# plans/2026-08-15-hexagonal-architecture.md) with its own compose project
# publishing the same host port 8091 — the outer Caddy targets the published
# port, so nothing here changes for routing.
# Redis (required by Infisical — Phase 5)
redis:
image: redis:7-alpine
restart: unless-stopped
profiles: ["infisical", "full"]
volumes:
- redis-data:/data
mem_limit: 128m
cpus: 0.5
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
# Infisical self-hosted (Phase 5 secrets management)
infisical:
image: infisical/infisical:v0.162.19
restart: unless-stopped
profiles: ["infisical", "full"]
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
environment:
ENCRYPTION_KEY: ${INFISICAL_ENCRYPTION_KEY:-dev-encryption-key-change-me}
JWT_SIGNUP_SECRET: ${INFISICAL_JWT_SIGNUP_SECRET:-dev-jwt-change-me}
JWT_REFRESH_SECRET: ${INFISICAL_JWT_REFRESH_SECRET:-dev-refresh-change-me}
JWT_AUTH_SECRET: ${INFISICAL_JWT_AUTH_SECRET:-dev-auth-change-me}
JWT_SERVICE_SECRET: ${INFISICAL_JWT_SERVICE_SECRET:-dev-service-change-me}
JWT_MFA_SECRET: ${INFISICAL_JWT_MFA_SECRET:-dev-mfa-change-me}
JWT_PROVIDER_SECRET: ${INFISICAL_JWT_PROVIDER_SECRET:-dev-provider-change-me}
SITE_URL: ${INFISICAL_SITE_URL:-http://localhost:8080}
SMTP_HOST: ""
DB_CONNECTION_URI: postgres://oikos:${OIKOS_DB_PASSWORD:-oikos_dev}@postgres:5432/infisical?sslmode=disable
REDIS_URL: redis://redis:6379
ports:
- "8080:8080"
mem_limit: 512m
cpus: 1.0
volumes:
pg-data:
redis-data: