596 lines
18 KiB
YAML
596 lines
18 KiB
YAML
services:
|
|
# ======================
|
|
# PostgreSQL Database
|
|
# ======================
|
|
postgres:
|
|
build:
|
|
context: ./docker/postgres
|
|
dockerfile: Dockerfile
|
|
container_name: mosaic-postgres
|
|
restart: unless-stopped
|
|
environment:
|
|
POSTGRES_USER: ${POSTGRES_USER:-mosaic}
|
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-mosaic_dev_password}
|
|
POSTGRES_DB: ${POSTGRES_DB:-mosaic}
|
|
# Performance tuning
|
|
POSTGRES_SHARED_BUFFERS: ${POSTGRES_SHARED_BUFFERS:-256MB}
|
|
POSTGRES_EFFECTIVE_CACHE_SIZE: ${POSTGRES_EFFECTIVE_CACHE_SIZE:-1GB}
|
|
POSTGRES_MAX_CONNECTIONS: ${POSTGRES_MAX_CONNECTIONS:-100}
|
|
ports:
|
|
- "${POSTGRES_PORT:-5432}:5432"
|
|
volumes:
|
|
- postgres_data:/var/lib/postgresql/data
|
|
- ./docker/postgres/init-scripts:/docker-entrypoint-initdb.d:ro
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-mosaic} -d ${POSTGRES_DB:-mosaic}"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
start_period: 30s
|
|
networks:
|
|
- mosaic-internal
|
|
profiles:
|
|
- database
|
|
- full
|
|
labels:
|
|
- "com.mosaic.service=database"
|
|
- "com.mosaic.description=PostgreSQL 17 with pgvector"
|
|
|
|
# ======================
|
|
# Valkey Cache
|
|
# ======================
|
|
valkey:
|
|
image: valkey/valkey:8-alpine
|
|
container_name: mosaic-valkey
|
|
restart: unless-stopped
|
|
command:
|
|
- valkey-server
|
|
- --maxmemory ${VALKEY_MAXMEMORY:-256mb}
|
|
- --maxmemory-policy noeviction
|
|
- --appendonly yes
|
|
ports:
|
|
- "${VALKEY_PORT:-6379}:6379"
|
|
volumes:
|
|
- valkey_data:/data
|
|
healthcheck:
|
|
test: ["CMD", "valkey-cli", "ping"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
start_period: 10s
|
|
networks:
|
|
- mosaic-internal
|
|
profiles:
|
|
- cache
|
|
- full
|
|
labels:
|
|
- "com.mosaic.service=cache"
|
|
- "com.mosaic.description=Valkey Redis-compatible cache"
|
|
|
|
# ======================
|
|
# Authentik PostgreSQL
|
|
# ======================
|
|
authentik-postgres:
|
|
image: postgres:17.7-alpine3.22
|
|
container_name: mosaic-authentik-postgres
|
|
restart: unless-stopped
|
|
environment:
|
|
POSTGRES_USER: ${AUTHENTIK_POSTGRES_USER:-authentik}
|
|
POSTGRES_PASSWORD: ${AUTHENTIK_POSTGRES_PASSWORD:-authentik_password}
|
|
POSTGRES_DB: ${AUTHENTIK_POSTGRES_DB:-authentik}
|
|
volumes:
|
|
- authentik_postgres_data:/var/lib/postgresql/data
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U ${AUTHENTIK_POSTGRES_USER:-authentik}"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
start_period: 20s
|
|
networks:
|
|
- mosaic-internal
|
|
profiles:
|
|
- authentik
|
|
- full
|
|
labels:
|
|
- "com.mosaic.service=auth-database"
|
|
- "com.mosaic.description=Authentik PostgreSQL database"
|
|
|
|
# ======================
|
|
# Authentik Redis
|
|
# ======================
|
|
authentik-redis:
|
|
image: valkey/valkey:8-alpine
|
|
container_name: mosaic-authentik-redis
|
|
restart: unless-stopped
|
|
command: valkey-server --save 60 1 --loglevel warning
|
|
volumes:
|
|
- authentik_redis_data:/data
|
|
healthcheck:
|
|
test: ["CMD", "valkey-cli", "ping"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
start_period: 10s
|
|
networks:
|
|
- mosaic-internal
|
|
profiles:
|
|
- authentik
|
|
- full
|
|
labels:
|
|
- "com.mosaic.service=auth-cache"
|
|
- "com.mosaic.description=Authentik Redis cache"
|
|
|
|
# ======================
|
|
# Authentik Server
|
|
# ======================
|
|
authentik-server:
|
|
image: ghcr.io/goauthentik/server:2024.12.1
|
|
container_name: mosaic-authentik-server
|
|
restart: unless-stopped
|
|
command: server
|
|
environment:
|
|
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:-change-this-to-a-random-secret}
|
|
AUTHENTIK_ERROR_REPORTING__ENABLED: ${AUTHENTIK_ERROR_REPORTING:-false}
|
|
AUTHENTIK_POSTGRESQL__HOST: authentik-postgres
|
|
AUTHENTIK_POSTGRESQL__PORT: 5432
|
|
AUTHENTIK_POSTGRESQL__NAME: ${AUTHENTIK_POSTGRES_DB:-authentik}
|
|
AUTHENTIK_POSTGRESQL__USER: ${AUTHENTIK_POSTGRES_USER:-authentik}
|
|
AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_POSTGRES_PASSWORD:-authentik_password}
|
|
AUTHENTIK_REDIS__HOST: authentik-redis
|
|
AUTHENTIK_REDIS__PORT: 6379
|
|
AUTHENTIK_BOOTSTRAP_PASSWORD: ${AUTHENTIK_BOOTSTRAP_PASSWORD:-admin}
|
|
AUTHENTIK_BOOTSTRAP_EMAIL: ${AUTHENTIK_BOOTSTRAP_EMAIL:-admin@localhost}
|
|
AUTHENTIK_COOKIE_DOMAIN: ${AUTHENTIK_COOKIE_DOMAIN:-.localhost}
|
|
ports:
|
|
- "${AUTHENTIK_PORT_HTTP:-9000}:9000"
|
|
- "${AUTHENTIK_PORT_HTTPS:-9443}:9443"
|
|
volumes:
|
|
- authentik_media:/media
|
|
- authentik_templates:/templates
|
|
depends_on:
|
|
authentik-postgres:
|
|
condition: service_healthy
|
|
authentik-redis:
|
|
condition: service_healthy
|
|
healthcheck:
|
|
test:
|
|
[
|
|
"CMD",
|
|
"wget",
|
|
"--no-verbose",
|
|
"--tries=1",
|
|
"--spider",
|
|
"http://localhost:9000/-/health/live/",
|
|
]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 90s
|
|
networks:
|
|
- mosaic-internal
|
|
- mosaic-public
|
|
profiles:
|
|
- authentik
|
|
- full
|
|
labels:
|
|
- "com.mosaic.service=auth-server"
|
|
- "com.mosaic.description=Authentik OIDC server"
|
|
# Traefik labels (activated when TRAEFIK_MODE=bundled or upstream)
|
|
- "traefik.enable=${TRAEFIK_ENABLE:-false}"
|
|
- "traefik.http.routers.mosaic-auth.rule=Host(`${MOSAIC_AUTH_DOMAIN:-auth.mosaic.local}`)"
|
|
- "traefik.http.routers.mosaic-auth.entrypoints=${TRAEFIK_ENTRYPOINT:-websecure}"
|
|
- "traefik.http.routers.mosaic-auth.tls=${TRAEFIK_TLS_ENABLED:-true}"
|
|
- "traefik.http.services.mosaic-auth.loadbalancer.server.port=9000"
|
|
- "traefik.docker.network=${TRAEFIK_DOCKER_NETWORK:-mosaic-public}"
|
|
# Let's Encrypt (if enabled)
|
|
- "traefik.http.routers.mosaic-auth.tls.certresolver=${TRAEFIK_CERTRESOLVER:-}"
|
|
|
|
# ======================
|
|
# Authentik Worker
|
|
# ======================
|
|
authentik-worker:
|
|
image: ghcr.io/goauthentik/server:2024.12.1
|
|
container_name: mosaic-authentik-worker
|
|
restart: unless-stopped
|
|
command: worker
|
|
environment:
|
|
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:-change-this-to-a-random-secret}
|
|
AUTHENTIK_ERROR_REPORTING__ENABLED: ${AUTHENTIK_ERROR_REPORTING:-false}
|
|
AUTHENTIK_POSTGRESQL__HOST: authentik-postgres
|
|
AUTHENTIK_POSTGRESQL__PORT: 5432
|
|
AUTHENTIK_POSTGRESQL__NAME: ${AUTHENTIK_POSTGRES_DB:-authentik}
|
|
AUTHENTIK_POSTGRESQL__USER: ${AUTHENTIK_POSTGRES_USER:-authentik}
|
|
AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_POSTGRES_PASSWORD:-authentik_password}
|
|
AUTHENTIK_REDIS__HOST: authentik-redis
|
|
AUTHENTIK_REDIS__PORT: 6379
|
|
volumes:
|
|
- authentik_media:/media
|
|
- authentik_certs:/certs
|
|
- authentik_templates:/templates
|
|
depends_on:
|
|
authentik-postgres:
|
|
condition: service_healthy
|
|
authentik-redis:
|
|
condition: service_healthy
|
|
networks:
|
|
- mosaic-internal
|
|
profiles:
|
|
- authentik
|
|
- full
|
|
labels:
|
|
- "com.mosaic.service=auth-worker"
|
|
- "com.mosaic.description=Authentik background worker"
|
|
|
|
# ======================
|
|
# Ollama (Optional AI Service)
|
|
# ======================
|
|
ollama:
|
|
image: ollama/ollama:latest
|
|
container_name: mosaic-ollama
|
|
restart: unless-stopped
|
|
ports:
|
|
- "${OLLAMA_PORT:-11434}:11434"
|
|
volumes:
|
|
- ollama_data:/root/.ollama
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:11434/api/tags"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 60s
|
|
networks:
|
|
- mosaic-internal
|
|
profiles:
|
|
- ollama
|
|
- full
|
|
labels:
|
|
- "com.mosaic.service=ai"
|
|
- "com.mosaic.description=Ollama LLM service"
|
|
# Uncomment if you have GPU support
|
|
# deploy:
|
|
# resources:
|
|
# reservations:
|
|
# devices:
|
|
# - driver: nvidia
|
|
# count: 1
|
|
# capabilities: [gpu]
|
|
|
|
# ======================
|
|
# OpenBao Secrets Management (Optional)
|
|
# ======================
|
|
openbao:
|
|
build:
|
|
context: ./docker/openbao
|
|
dockerfile: Dockerfile
|
|
container_name: mosaic-openbao
|
|
restart: unless-stopped
|
|
user: root
|
|
ports:
|
|
- "127.0.0.1:${OPENBAO_PORT:-8200}:8200"
|
|
volumes:
|
|
- openbao_data:/openbao/data
|
|
- openbao_init:/openbao/init
|
|
environment:
|
|
VAULT_ADDR: http://0.0.0.0:8200
|
|
SKIP_SETCAP: "true"
|
|
entrypoint: ["dumb-init", "--"]
|
|
command: ["bao", "server", "-config=/openbao/config/config.hcl"]
|
|
cap_add:
|
|
- IPC_LOCK
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "nc -z 127.0.0.1 8200 || exit 1"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
start_period: 10s
|
|
networks:
|
|
- mosaic-internal
|
|
profiles:
|
|
- openbao
|
|
- full
|
|
labels:
|
|
- "com.mosaic.service=secrets"
|
|
- "com.mosaic.description=OpenBao secrets management"
|
|
|
|
openbao-init:
|
|
build:
|
|
context: ./docker/openbao
|
|
dockerfile: Dockerfile
|
|
container_name: mosaic-openbao-init
|
|
restart: unless-stopped
|
|
user: root
|
|
volumes:
|
|
- openbao_init:/openbao/init
|
|
environment:
|
|
VAULT_ADDR: http://openbao:8200
|
|
command: ["/openbao/init.sh"]
|
|
depends_on:
|
|
openbao:
|
|
condition: service_healthy
|
|
networks:
|
|
- mosaic-internal
|
|
profiles:
|
|
- openbao
|
|
- full
|
|
labels:
|
|
- "com.mosaic.service=secrets-init"
|
|
- "com.mosaic.description=OpenBao auto-initialization sidecar"
|
|
|
|
# ======================
|
|
# Traefik Reverse Proxy (Optional - Bundled Mode)
|
|
# ======================
|
|
# Enable with: COMPOSE_PROFILES=traefik-bundled or --profile traefik-bundled
|
|
# Set TRAEFIK_MODE=bundled in .env
|
|
traefik:
|
|
image: traefik:v3.2
|
|
container_name: mosaic-traefik
|
|
restart: unless-stopped
|
|
command:
|
|
- "--configFile=/etc/traefik/traefik.yml"
|
|
ports:
|
|
- "${TRAEFIK_HTTP_PORT:-80}:80"
|
|
- "${TRAEFIK_HTTPS_PORT:-443}:443"
|
|
- "${TRAEFIK_DASHBOARD_PORT:-8080}:8080"
|
|
volumes:
|
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
|
- ./docker/traefik/traefik.yml:/etc/traefik/traefik.yml:ro
|
|
- ./docker/traefik/dynamic:/etc/traefik/dynamic:ro
|
|
- traefik_letsencrypt:/letsencrypt
|
|
environment:
|
|
- TRAEFIK_ACME_EMAIL=${TRAEFIK_ACME_EMAIL:-}
|
|
networks:
|
|
- mosaic-public
|
|
profiles:
|
|
- traefik-bundled
|
|
- full
|
|
labels:
|
|
- "com.mosaic.service=reverse-proxy"
|
|
- "com.mosaic.description=Traefik reverse proxy and load balancer"
|
|
healthcheck:
|
|
test: ["CMD", "traefik", "healthcheck", "--ping"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 20s
|
|
|
|
# ======================
|
|
# Mosaic API
|
|
# ======================
|
|
api:
|
|
build:
|
|
context: .
|
|
dockerfile: ./apps/api/Dockerfile
|
|
args:
|
|
- NODE_ENV=production
|
|
container_name: mosaic-api
|
|
restart: unless-stopped
|
|
environment:
|
|
NODE_ENV: production
|
|
# API Configuration - PORT is what NestJS reads
|
|
PORT: ${API_PORT:-3001}
|
|
API_HOST: ${API_HOST:-0.0.0.0}
|
|
# Database
|
|
DATABASE_URL: postgresql://${POSTGRES_USER:-mosaic}:${POSTGRES_PASSWORD:-mosaic_dev_password}@postgres:5432/${POSTGRES_DB:-mosaic}
|
|
# Cache
|
|
VALKEY_URL: redis://valkey:6379
|
|
# Authentication
|
|
OIDC_ENABLED: ${OIDC_ENABLED:-false}
|
|
OIDC_ISSUER: ${OIDC_ISSUER}
|
|
OIDC_CLIENT_ID: ${OIDC_CLIENT_ID}
|
|
OIDC_CLIENT_SECRET: ${OIDC_CLIENT_SECRET}
|
|
OIDC_REDIRECT_URI: ${OIDC_REDIRECT_URI:-http://localhost:3001/auth/callback}
|
|
# JWT
|
|
JWT_SECRET: ${JWT_SECRET:-change-this-to-a-random-secret}
|
|
JWT_EXPIRATION: ${JWT_EXPIRATION:-24h}
|
|
# Better Auth
|
|
BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET}
|
|
# Security
|
|
CSRF_SECRET: ${CSRF_SECRET}
|
|
ENCRYPTION_KEY: ${ENCRYPTION_KEY}
|
|
# Ollama (optional)
|
|
OLLAMA_ENDPOINT: ${OLLAMA_ENDPOINT:-http://ollama:11434}
|
|
# OpenBao (optional)
|
|
OPENBAO_ADDR: ${OPENBAO_ADDR:-http://openbao:8200}
|
|
volumes:
|
|
- openbao_init:/openbao/init:ro
|
|
ports:
|
|
- "${API_PORT:-3001}:${API_PORT:-3001}"
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
valkey:
|
|
condition: service_healthy
|
|
healthcheck:
|
|
test:
|
|
[
|
|
"CMD-SHELL",
|
|
'node -e "require(''http'').get(''http://localhost:${API_PORT:-3001}/health'', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"',
|
|
]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 40s
|
|
networks:
|
|
- mosaic-internal
|
|
- mosaic-public
|
|
labels:
|
|
- "com.mosaic.service=api"
|
|
- "com.mosaic.description=Mosaic NestJS API"
|
|
# Traefik labels (activated when TRAEFIK_MODE=bundled or upstream)
|
|
- "traefik.enable=${TRAEFIK_ENABLE:-false}"
|
|
- "traefik.http.routers.mosaic-api.rule=Host(`${MOSAIC_API_DOMAIN:-api.mosaic.local}`)"
|
|
- "traefik.http.routers.mosaic-api.entrypoints=${TRAEFIK_ENTRYPOINT:-websecure}"
|
|
- "traefik.http.routers.mosaic-api.tls=${TRAEFIK_TLS_ENABLED:-true}"
|
|
- "traefik.http.services.mosaic-api.loadbalancer.server.port=${API_PORT:-3001}"
|
|
- "traefik.docker.network=${TRAEFIK_DOCKER_NETWORK:-mosaic-public}"
|
|
# Let's Encrypt (if enabled)
|
|
- "traefik.http.routers.mosaic-api.tls.certresolver=${TRAEFIK_CERTRESOLVER:-}"
|
|
|
|
# ======================
|
|
# Mosaic Orchestrator
|
|
# ======================
|
|
orchestrator:
|
|
build:
|
|
context: .
|
|
dockerfile: ./apps/orchestrator/Dockerfile
|
|
container_name: mosaic-orchestrator
|
|
restart: unless-stopped
|
|
# Run as non-root user (node:node, UID 1000)
|
|
user: "1000:1000"
|
|
environment:
|
|
NODE_ENV: production
|
|
# Orchestrator Configuration
|
|
ORCHESTRATOR_PORT: 3001
|
|
AI_PROVIDER: ${AI_PROVIDER:-ollama}
|
|
# Valkey
|
|
VALKEY_URL: redis://valkey:6379
|
|
# Claude API (required only when AI_PROVIDER=claude)
|
|
CLAUDE_API_KEY: ${CLAUDE_API_KEY}
|
|
# Docker
|
|
DOCKER_SOCKET: /var/run/docker.sock
|
|
# Git
|
|
GIT_USER_NAME: "Mosaic Orchestrator"
|
|
GIT_USER_EMAIL: "orchestrator@mosaicstack.dev"
|
|
# Security
|
|
KILLSWITCH_ENABLED: true
|
|
SANDBOX_ENABLED: true
|
|
ports:
|
|
- "3002:3001"
|
|
volumes:
|
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
|
- orchestrator_workspace:/workspace
|
|
depends_on:
|
|
valkey:
|
|
condition: service_healthy
|
|
api:
|
|
condition: service_healthy
|
|
healthcheck:
|
|
test:
|
|
[
|
|
"CMD-SHELL",
|
|
'node -e "require(''http'').get(''http://localhost:3001/health'', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"',
|
|
]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 40s
|
|
networks:
|
|
- mosaic-internal
|
|
# Security hardening
|
|
security_opt:
|
|
- no-new-privileges:true
|
|
cap_drop:
|
|
- ALL
|
|
cap_add:
|
|
- NET_BIND_SERVICE
|
|
read_only: false # Cannot be read-only due to workspace writes
|
|
tmpfs:
|
|
- /tmp:noexec,nosuid,size=100m
|
|
labels:
|
|
- "com.mosaic.service=orchestrator"
|
|
- "com.mosaic.description=Mosaic Agent Orchestrator"
|
|
- "com.mosaic.security=hardened"
|
|
- "com.mosaic.security.non-root=true"
|
|
- "com.mosaic.security.capabilities=minimal"
|
|
|
|
# ======================
|
|
# Mosaic Web
|
|
# ======================
|
|
web:
|
|
build:
|
|
context: .
|
|
dockerfile: ./apps/web/Dockerfile
|
|
args:
|
|
- NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL:-http://localhost:3001}
|
|
container_name: mosaic-web
|
|
restart: unless-stopped
|
|
environment:
|
|
NODE_ENV: production
|
|
PORT: ${WEB_PORT:-3000}
|
|
NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:3001}
|
|
ports:
|
|
- "${WEB_PORT:-3000}:${WEB_PORT:-3000}"
|
|
depends_on:
|
|
api:
|
|
condition: service_healthy
|
|
healthcheck:
|
|
test:
|
|
[
|
|
"CMD-SHELL",
|
|
'node -e "require(''http'').get(''http://localhost:${WEB_PORT:-3000}'', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"',
|
|
]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 40s
|
|
networks:
|
|
- mosaic-public
|
|
labels:
|
|
- "com.mosaic.service=web"
|
|
- "com.mosaic.description=Mosaic Next.js Web App"
|
|
# Traefik labels (activated when TRAEFIK_MODE=bundled or upstream)
|
|
- "traefik.enable=${TRAEFIK_ENABLE:-false}"
|
|
- "traefik.http.routers.mosaic-web.rule=Host(`${MOSAIC_WEB_DOMAIN:-mosaic.local}`)"
|
|
- "traefik.http.routers.mosaic-web.entrypoints=${TRAEFIK_ENTRYPOINT:-websecure}"
|
|
- "traefik.http.routers.mosaic-web.tls=${TRAEFIK_TLS_ENABLED:-true}"
|
|
- "traefik.http.services.mosaic-web.loadbalancer.server.port=${WEB_PORT:-3000}"
|
|
- "traefik.docker.network=${TRAEFIK_DOCKER_NETWORK:-mosaic-public}"
|
|
# Let's Encrypt (if enabled)
|
|
- "traefik.http.routers.mosaic-web.tls.certresolver=${TRAEFIK_CERTRESOLVER:-}"
|
|
|
|
# ======================
|
|
# Volumes
|
|
# ======================
|
|
volumes:
|
|
postgres_data:
|
|
name: mosaic-postgres-data
|
|
driver: local
|
|
valkey_data:
|
|
name: mosaic-valkey-data
|
|
driver: local
|
|
authentik_postgres_data:
|
|
name: mosaic-authentik-postgres-data
|
|
driver: local
|
|
authentik_redis_data:
|
|
name: mosaic-authentik-redis-data
|
|
driver: local
|
|
authentik_media:
|
|
name: mosaic-authentik-media
|
|
driver: local
|
|
authentik_certs:
|
|
name: mosaic-authentik-certs
|
|
driver: local
|
|
authentik_templates:
|
|
name: mosaic-authentik-templates
|
|
driver: local
|
|
ollama_data:
|
|
name: mosaic-ollama-data
|
|
driver: local
|
|
openbao_data:
|
|
name: mosaic-openbao-data
|
|
driver: local
|
|
openbao_init:
|
|
name: mosaic-openbao-init
|
|
driver: local
|
|
traefik_letsencrypt:
|
|
name: mosaic-traefik-letsencrypt
|
|
driver: local
|
|
orchestrator_workspace:
|
|
name: mosaic-orchestrator-workspace
|
|
driver: local
|
|
|
|
# ======================
|
|
# Networks
|
|
# ======================
|
|
networks:
|
|
# Internal network for database/cache isolation
|
|
# Note: NOT marked as 'internal: true' because API needs external access
|
|
# for Authentik OIDC and external Ollama services
|
|
mosaic-internal:
|
|
name: mosaic-internal
|
|
driver: bridge
|
|
# Public network for services that need external access
|
|
mosaic-public:
|
|
name: mosaic-public
|
|
driver: bridge
|