From a8d426e3c03ac810f089e7f5df920913373a1f55 Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Tue, 3 Mar 2026 03:45:46 +0000 Subject: [PATCH] infra: migrate postgres to shared openbrain_brain-db (#664) Co-authored-by: Jason Woltje Co-committed-by: Jason Woltje --- docker-compose.swarm.portainer.yml | 105 ++++++++++++++++++++--------- 1 file changed, 72 insertions(+), 33 deletions(-) diff --git a/docker-compose.swarm.portainer.yml b/docker-compose.swarm.portainer.yml index af0e4eb..beb6891 100644 --- a/docker-compose.swarm.portainer.yml +++ b/docker-compose.swarm.portainer.yml @@ -9,6 +9,8 @@ # - OpenBao: Standalone container (see docker-compose.openbao.yml) # - Authentik: External OIDC provider # - Ollama: External AI inference +# - PostgreSQL: Provided by the openbrain stack (openbrain_brain-db) +# Deploy openbrain stack before this stack. # # Usage (Portainer): # 1. Stacks -> Add Stack -> Upload or paste @@ -36,37 +38,71 @@ # Required vars use plain ${VAR} — the app validates at startup. # # ============================================== +# DATABASE (openbrain_brain-db — external) +# ============================================== +# +# This stack uses the PostgreSQL instance from the openbrain stack. +# The openbrain stack must be deployed first and its brain-internal +# overlay network must exist. +# +# Required env vars for DB access: +# BRAIN_DB_ADMIN_USER — openbrain superuser (default: openbrain) +# BRAIN_DB_ADMIN_PASSWORD — openbrain superuser password +# (must match openbrain stack POSTGRES_PASSWORD) +# POSTGRES_USER — mosaic application DB user (created by mosaic-db-init) +# POSTGRES_PASSWORD — mosaic application DB password +# POSTGRES_DB — mosaic application database name (default: mosaic) +# +# ============================================== services: # ============================================ - # CORE INFRASTRUCTURE + # DATABASE INIT # ============================================ # ====================== - # PostgreSQL Database + # Mosaic Database Init # ====================== - postgres: - image: git.mosaicstack.dev/mosaic/stack-postgres:${IMAGE_TAG:-latest} + # Creates the mosaic application user and database in the shared + # openbrain PostgreSQL instance (openbrain_brain-db). + # Runs once and exits. Idempotent — safe to run on every deploy. + mosaic-db-init: + image: postgres:17-alpine environment: - POSTGRES_USER: ${POSTGRES_USER} - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} - POSTGRES_DB: ${POSTGRES_DB} - POSTGRES_SHARED_BUFFERS: ${POSTGRES_SHARED_BUFFERS:-256MB} - POSTGRES_EFFECTIVE_CACHE_SIZE: ${POSTGRES_EFFECTIVE_CACHE_SIZE:-1GB} - POSTGRES_MAX_CONNECTIONS: ${POSTGRES_MAX_CONNECTIONS:-100} - volumes: - - postgres_data:/var/lib/postgresql/data - healthcheck: - test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"] - interval: 10s - timeout: 5s - retries: 5 - start_period: 30s + PGHOST: openbrain_brain-db + PGPORT: 5432 + PGUSER: ${BRAIN_DB_ADMIN_USER:-openbrain} + PGPASSWORD: ${BRAIN_DB_ADMIN_PASSWORD} + MOSAIC_USER: ${POSTGRES_USER} + MOSAIC_PASSWORD: ${POSTGRES_PASSWORD} + MOSAIC_DB: ${POSTGRES_DB:-mosaic} + entrypoint: ["sh", "-c"] + command: + - | + until pg_isready -h openbrain_brain-db -p 5432 -U $${PGUSER}; do + echo "Waiting for openbrain_brain-db..." + sleep 2 + done + echo "Database ready. Creating mosaic user and database..." + + psql -h openbrain_brain-db -U $${PGUSER} -tc "SELECT 1 FROM pg_roles WHERE rolname='$${MOSAIC_USER}'" | grep -q 1 || \ + psql -h openbrain_brain-db -U $${PGUSER} -c "CREATE USER $${MOSAIC_USER} WITH PASSWORD '$${MOSAIC_PASSWORD}';" + + psql -h openbrain_brain-db -U $${PGUSER} -tc "SELECT 1 FROM pg_database WHERE datname='$${MOSAIC_DB}'" | grep -q 1 || \ + psql -h openbrain_brain-db -U $${PGUSER} -c "CREATE DATABASE $${MOSAIC_DB} OWNER $${MOSAIC_USER} ENCODING 'UTF8' LC_COLLATE='C' LC_CTYPE='C' TEMPLATE template0;" + + echo "Mosaic database ready: $${MOSAIC_DB}" networks: - - internal + - openbrain-brain-internal deploy: restart_policy: condition: on-failure + delay: 5s + max_attempts: 5 + + # ============================================ + # CORE INFRASTRUCTURE + # ============================================ # ====================== # Valkey Cache @@ -105,7 +141,7 @@ services: NODE_ENV: production PORT: ${API_PORT:-3001} API_HOST: ${API_HOST:-0.0.0.0} - DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB} + DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@openbrain_brain-db:5432/${POSTGRES_DB:-mosaic} VALKEY_URL: redis://valkey:6379 # Auth (external Authentik) OIDC_ENABLED: ${OIDC_ENABLED:-false} @@ -163,6 +199,7 @@ services: networks: - internal - traefik-public + - openbrain-brain-internal deploy: restart_policy: condition: on-failure @@ -307,36 +344,36 @@ services: # ====================== # Synapse Database Init # ====================== - # Creates the 'synapse' database in the shared PostgreSQL instance. + # Creates the 'synapse' database in the shared openbrain PostgreSQL instance. # Runs once and exits. Idempotent — safe to run on every deploy. synapse-db-init: image: postgres:17-alpine environment: - PGHOST: postgres + PGHOST: openbrain_brain-db PGPORT: 5432 - PGUSER: ${POSTGRES_USER} - PGPASSWORD: ${POSTGRES_PASSWORD} + PGUSER: ${BRAIN_DB_ADMIN_USER:-openbrain} + PGPASSWORD: ${BRAIN_DB_ADMIN_PASSWORD} SYNAPSE_DB: ${SYNAPSE_POSTGRES_DB} SYNAPSE_USER: ${SYNAPSE_POSTGRES_USER} SYNAPSE_PASSWORD: ${SYNAPSE_POSTGRES_PASSWORD} entrypoint: ["sh", "-c"] command: - | - until pg_isready -h postgres -p 5432 -U $${PGUSER}; do - echo "Waiting for PostgreSQL..." + until pg_isready -h openbrain_brain-db -p 5432 -U $${PGUSER}; do + echo "Waiting for openbrain_brain-db..." sleep 2 done - echo "PostgreSQL is ready. Creating Synapse database and user..." + echo "Database ready. Creating Synapse user and database..." - psql -h postgres -U $${PGUSER} -tc "SELECT 1 FROM pg_roles WHERE rolname='$${SYNAPSE_USER}'" | grep -q 1 || \ - psql -h postgres -U $${PGUSER} -c "CREATE USER $${SYNAPSE_USER} WITH PASSWORD '$${SYNAPSE_PASSWORD}';" + psql -h openbrain_brain-db -U $${PGUSER} -tc "SELECT 1 FROM pg_roles WHERE rolname='$${SYNAPSE_USER}'" | grep -q 1 || \ + psql -h openbrain_brain-db -U $${PGUSER} -c "CREATE USER $${SYNAPSE_USER} WITH PASSWORD '$${SYNAPSE_PASSWORD}';" - psql -h postgres -U $${PGUSER} -tc "SELECT 1 FROM pg_database WHERE datname='$${SYNAPSE_DB}'" | grep -q 1 || \ - psql -h postgres -U $${PGUSER} -c "CREATE DATABASE $${SYNAPSE_DB} OWNER $${SYNAPSE_USER} ENCODING 'UTF8' LC_COLLATE='C' LC_CTYPE='C' TEMPLATE template0;" + psql -h openbrain_brain-db -U $${PGUSER} -tc "SELECT 1 FROM pg_database WHERE datname='$${SYNAPSE_DB}'" | grep -q 1 || \ + psql -h openbrain_brain-db -U $${PGUSER} -c "CREATE DATABASE $${SYNAPSE_DB} OWNER $${SYNAPSE_USER} ENCODING 'UTF8' LC_COLLATE='C' LC_CTYPE='C' TEMPLATE template0;" echo "Synapse database ready: $${SYNAPSE_DB}" networks: - - internal + - openbrain-brain-internal deploy: restart_policy: condition: on-failure @@ -451,7 +488,6 @@ services: # Volumes # ====================== volumes: - postgres_data: valkey_data: orchestrator_workspace: speaches_models: @@ -464,3 +500,6 @@ networks: driver: overlay traefik-public: external: true + openbrain-brain-internal: + external: true + name: openbrain_brain-internal