feat(swarm): add coordinator service and reorganize compose files
- Add coordinator service to docker-compose.swarm.portainer.yml and docker-compose.swarm.yml with full environment config and healthcheck - Add ANTHROPIC_API_KEY and coordinator settings to .env.swarm.example - Move docker-compose.override.yml.example and docker-compose.prod.yml into docker/ directory - Add *.bak to .gitignore Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
147
docker/docker-compose.override.yml.example
Normal file
147
docker/docker-compose.override.yml.example
Normal file
@@ -0,0 +1,147 @@
|
||||
# Docker Compose Override Example
|
||||
# Copy this file to docker-compose.override.yml to customize your deployment
|
||||
# Usage: docker compose up (automatically uses both docker-compose.yml and docker-compose.override.yml)
|
||||
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
# ======================
|
||||
# Example: Use External PostgreSQL
|
||||
# ======================
|
||||
# Uncomment to disable the bundled PostgreSQL and use an external instance
|
||||
# postgres:
|
||||
# profiles:
|
||||
# - disabled
|
||||
|
||||
# api:
|
||||
# environment:
|
||||
# DATABASE_URL: postgresql://user:password@external-postgres.example.com:5432/mosaic
|
||||
|
||||
# ======================
|
||||
# Example: Use External Valkey/Redis
|
||||
# ======================
|
||||
# Uncomment to disable the bundled Valkey and use an external instance
|
||||
# valkey:
|
||||
# profiles:
|
||||
# - disabled
|
||||
|
||||
# api:
|
||||
# environment:
|
||||
# VALKEY_URL: redis://external-redis.example.com:6379
|
||||
|
||||
# ======================
|
||||
# Example: Use External Ollama
|
||||
# ======================
|
||||
# Uncomment to disable the bundled Ollama and use an external instance
|
||||
# ollama:
|
||||
# profiles:
|
||||
# - disabled
|
||||
|
||||
# api:
|
||||
# environment:
|
||||
# OLLAMA_ENDPOINT: http://external-ollama.example.com:11434
|
||||
|
||||
# ======================
|
||||
# Example: Development Overrides
|
||||
# ======================
|
||||
# Uncomment for development-specific settings
|
||||
# postgres:
|
||||
# ports:
|
||||
# - "5432:5432"
|
||||
# command:
|
||||
# - "postgres"
|
||||
# - "-c"
|
||||
# - "log_statement=all"
|
||||
# - "-c"
|
||||
# - "log_duration=on"
|
||||
|
||||
# api:
|
||||
# environment:
|
||||
# NODE_ENV: development
|
||||
# LOG_LEVEL: debug
|
||||
# volumes:
|
||||
# - ./apps/api/src:/app/apps/api/src:ro
|
||||
|
||||
# web:
|
||||
# environment:
|
||||
# NODE_ENV: development
|
||||
# volumes:
|
||||
# - ./apps/web/src:/app/apps/web/src:ro
|
||||
|
||||
# ======================
|
||||
# Example: Enable GPU for Ollama
|
||||
# ======================
|
||||
# Uncomment to enable GPU support for Ollama (requires NVIDIA Docker runtime)
|
||||
# ollama:
|
||||
# deploy:
|
||||
# resources:
|
||||
# reservations:
|
||||
# devices:
|
||||
# - driver: nvidia
|
||||
# count: 1
|
||||
# capabilities: [gpu]
|
||||
|
||||
# ======================
|
||||
# Example: Traefik Upstream Mode
|
||||
# ======================
|
||||
# Connect to an existing external Traefik instance
|
||||
# 1. Set TRAEFIK_MODE=upstream in .env
|
||||
# 2. Set TRAEFIK_ENABLE=true in .env
|
||||
# 3. Set TRAEFIK_NETWORK=traefik-public (or your network name)
|
||||
# 4. Uncomment the network section below
|
||||
# 5. Ensure external Traefik network exists: docker network create traefik-public
|
||||
#
|
||||
# api:
|
||||
# networks:
|
||||
# - traefik-public
|
||||
#
|
||||
# web:
|
||||
# networks:
|
||||
# - traefik-public
|
||||
#
|
||||
# authentik-server:
|
||||
# networks:
|
||||
# - traefik-public
|
||||
|
||||
# ======================
|
||||
# Example: Traefik with Custom Middleware
|
||||
# ======================
|
||||
# Add authentication or other middleware to routes
|
||||
# traefik:
|
||||
# labels:
|
||||
# # Basic auth middleware
|
||||
# - "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$xyz..."
|
||||
#
|
||||
# api:
|
||||
# labels:
|
||||
# # Apply middleware to API router
|
||||
# - "traefik.http.routers.mosaic-api.middlewares=auth@docker"
|
||||
|
||||
# ======================
|
||||
# Example: Traefik with Let's Encrypt (Production)
|
||||
# ======================
|
||||
# Enable automatic SSL with Let's Encrypt
|
||||
# 1. Set TRAEFIK_ACME_EMAIL in .env
|
||||
# 2. Set TRAEFIK_CERTRESOLVER=letsencrypt in .env
|
||||
# 3. Uncomment Traefik ACME configuration in docker/traefik/traefik.yml
|
||||
# 4. Ensure ports 80 and 443 are accessible from the internet
|
||||
#
|
||||
# No additional overrides needed - configured in traefik.yml
|
||||
|
||||
# ======================
|
||||
# Example: Traefik with Custom Domains
|
||||
# ======================
|
||||
# Override default domains for production deployment
|
||||
# Set these in .env instead:
|
||||
# MOSAIC_API_DOMAIN=api.example.com
|
||||
# MOSAIC_WEB_DOMAIN=example.com
|
||||
# MOSAIC_AUTH_DOMAIN=auth.example.com
|
||||
|
||||
# ======================
|
||||
# Networks
|
||||
# ======================
|
||||
# Uncomment when using upstream Traefik mode
|
||||
# networks:
|
||||
# traefik-public:
|
||||
# external: true
|
||||
# name: ${TRAEFIK_NETWORK:-traefik-public}
|
||||
179
docker/docker-compose.prod.yml
Normal file
179
docker/docker-compose.prod.yml
Normal file
@@ -0,0 +1,179 @@
|
||||
# Production Docker Compose - Uses pre-built images from Gitea Packages
|
||||
#
|
||||
# Prerequisites:
|
||||
# - Images built and pushed to git.mosaicstack.dev/mosaic/*
|
||||
# - .env file configured with production values
|
||||
#
|
||||
# Usage:
|
||||
# docker compose -f docker-compose.prod.yml up -d
|
||||
#
|
||||
# For Portainer:
|
||||
# - Stack → Add Stack → Repository
|
||||
# - Compose file: docker-compose.prod.yml
|
||||
|
||||
services:
|
||||
# ======================
|
||||
# PostgreSQL Database
|
||||
# ======================
|
||||
postgres:
|
||||
image: git.mosaicstack.dev/mosaic/postgres:latest
|
||||
container_name: mosaic-postgres
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_USER: ${POSTGRES_USER:-mosaic}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
POSTGRES_DB: ${POSTGRES_DB:-mosaic}
|
||||
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:-mosaic} -d ${POSTGRES_DB:-mosaic}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
networks:
|
||||
- mosaic-internal
|
||||
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 allkeys-lru
|
||||
- --appendonly yes
|
||||
volumes:
|
||||
- valkey_data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "valkey-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 10s
|
||||
networks:
|
||||
- mosaic-internal
|
||||
labels:
|
||||
- "com.mosaic.service=cache"
|
||||
- "com.mosaic.description=Valkey Redis-compatible cache"
|
||||
|
||||
# ======================
|
||||
# Mosaic API
|
||||
# ======================
|
||||
api:
|
||||
image: git.mosaicstack.dev/mosaic/api:latest
|
||||
container_name: mosaic-api
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
NODE_ENV: production
|
||||
PORT: ${API_PORT:-3001}
|
||||
API_HOST: ${API_HOST:-0.0.0.0}
|
||||
DATABASE_URL: postgresql://${POSTGRES_USER:-mosaic}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-mosaic}
|
||||
VALKEY_URL: redis://valkey:6379
|
||||
OIDC_ISSUER: ${OIDC_ISSUER}
|
||||
OIDC_CLIENT_ID: ${OIDC_CLIENT_ID}
|
||||
OIDC_CLIENT_SECRET: ${OIDC_CLIENT_SECRET}
|
||||
OIDC_REDIRECT_URI: ${OIDC_REDIRECT_URI}
|
||||
JWT_SECRET: ${JWT_SECRET}
|
||||
JWT_EXPIRATION: ${JWT_EXPIRATION:-24h}
|
||||
OLLAMA_ENDPOINT: ${OLLAMA_ENDPOINT:-http://ollama:11434}
|
||||
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.enable=${TRAEFIK_ENABLE:-false}"
|
||||
- "traefik.http.routers.mosaic-api.rule=Host(`${MOSAIC_API_DOMAIN:-api.mosaicstack.dev}`)"
|
||||
- "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}"
|
||||
- "traefik.http.routers.mosaic-api.tls.certresolver=${TRAEFIK_CERTRESOLVER:-}"
|
||||
|
||||
# ======================
|
||||
# Mosaic Web
|
||||
# ======================
|
||||
web:
|
||||
image: git.mosaicstack.dev/mosaic/web:latest
|
||||
container_name: mosaic-web
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
NODE_ENV: production
|
||||
PORT: ${WEB_PORT:-3000}
|
||||
NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-https://api.mosaicstack.dev}
|
||||
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.enable=${TRAEFIK_ENABLE:-false}"
|
||||
- "traefik.http.routers.mosaic-web.rule=Host(`${MOSAIC_WEB_DOMAIN:-app.mosaicstack.dev}`)"
|
||||
- "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}"
|
||||
- "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
|
||||
|
||||
# ======================
|
||||
# Networks
|
||||
# ======================
|
||||
networks:
|
||||
mosaic-internal:
|
||||
name: mosaic-internal
|
||||
driver: bridge
|
||||
mosaic-public:
|
||||
name: mosaic-public
|
||||
driver: bridge
|
||||
Reference in New Issue
Block a user