Files
HiveGrid-Wireframes/hivegrid-cloud/docker-compose.yml
T

234 lines
8.2 KiB
YAML

services:
redis:
image: redis:7-alpine
ports:
- "6379:6379"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 10
pgbouncer:
# Connection pooler in front of Postgres for application traffic (DATABASE_URL).
# Apps point DATABASE_URL at pgbouncer:6432, DIRECT_URL stays on postgres:5432
# so Prisma migrate can keep prepared statements. See docs/ops/pgbouncer.md.
image: edoburu/pgbouncer:latest
# No `ports:` mapping — pgbouncer must only be reachable inside the Docker
# network. Public-facing 6432 would expose the pool to the open internet.
volumes:
- ./infra/pgbouncer/pgbouncer.ini:/etc/pgbouncer/pgbouncer.ini:ro
- ./infra/pgbouncer/userlist.txt:/etc/pgbouncer/userlist.txt:ro
healthcheck:
# pg_isready is shipped inside the edoburu image; queries the pool listener
# without holding a server-side connection.
test: ["CMD", "pg_isready", "-h", "127.0.0.1", "-p", "6432", "-U", "pgb_admin"]
interval: 10s
timeout: 3s
retries: 5
start_period: 10s
restart: unless-stopped
clamav:
image: clamav/clamav:stable
volumes:
- clamav-db:/var/lib/clamav
ports:
- "3310:3310"
healthcheck:
# CLAMD_STARTUP_TIMEOUT only matters for the first boot — freshclam pulls
# ~250MB of signatures before clamd starts listening. Allow ~20 minutes
# for cold starts; after that the check passes in <2s.
test: ["CMD", "clamdscan", "--ping", "1"]
interval: 30s
timeout: 5s
retries: 40
start_period: 1200s
restart: unless-stopped
# Worker is split into five runtime variants — same image, same code,
# different WORKER_QUEUE_GROUP env. See docs/ops/worker-queues.md.
# `worker` is kept as a YAML anchor so the five group services share a
# single build context. Only worker-general depends on ClamAV because it
# owns the file-scan queue; other worker groups override depends_on to avoid
# blocking on first-boot signature downloads.
worker-general: &worker-base
build:
context: .
target: worker
environment:
- WORKER_ENABLED=${WORKER_ENABLED:-false}
- WORKER_QUEUE_GROUP=general
- WORKER_CONCURRENCY_GENERAL=${WORKER_CONCURRENCY_GENERAL:-10}
- WORKER_HEALTH_PORT=9101
- WORKER_ADMIN_PORT=9201
- BULLMQ_REDIS_URL=${BULLMQ_REDIS_URL:-redis://redis:6379/0}
- DATABASE_URL=${DATABASE_URL:-}
- APP_URL=${APP_URL:-}
- OUTBOX_DISPATCHER_ENABLED=${OUTBOX_DISPATCHER_ENABLED:-false}
- OUTBOX_DISPATCHER_REQUIRED=${OUTBOX_DISPATCHER_REQUIRED:-false}
- OUTBOX_DISPATCH_CONCURRENCY=${OUTBOX_DISPATCH_CONCURRENCY:-10}
- WORKFLOW_TRIGGER_EXECUTOR_MODE=${WORKFLOW_TRIGGER_EXECUTOR_MODE:-http}
- WORKFLOW_TRIGGER_EXECUTOR_URL=${WORKFLOW_TRIGGER_EXECUTOR_URL:-}
- API_ACCESS_TOKEN=${API_ACCESS_TOKEN:-}
- WORKFLOW_TRIGGER_EXECUTOR_TIMEOUT_MS=${WORKFLOW_TRIGGER_EXECUTOR_TIMEOUT_MS:-30000}
- WORKFLOW_TRIGGER_OUTBOX_ENABLED=${WORKFLOW_TRIGGER_OUTBOX_ENABLED:-true}
- WORKFLOW_TRIGGER_OUTBOX_CONCURRENCY=${WORKFLOW_TRIGGER_OUTBOX_CONCURRENCY:-5}
- WORKFLOW_TRIGGER_OUTBOX_REQUIRED=${WORKFLOW_TRIGGER_OUTBOX_REQUIRED:-false}
- SCAN_QUEUE_ENABLED=${SCAN_QUEUE_ENABLED:-false}
- CLAMAV_HOST=${CLAMAV_HOST:-clamav}
- CLAMAV_PORT=${CLAMAV_PORT:-3310}
- CLAMAV_TIMEOUT_MS=${CLAMAV_TIMEOUT_MS:-30000}
depends_on:
redis:
condition: service_healthy
clamav:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:9101/healthz || exit 1"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
worker-mail:
<<: *worker-base
environment:
- WORKER_ENABLED=${WORKER_ENABLED:-false}
- WORKER_QUEUE_GROUP=mail
- WORKER_CONCURRENCY_MAIL=${WORKER_CONCURRENCY_MAIL:-5}
- WORKER_HEALTH_PORT=9102
- WORKER_ADMIN_PORT=9202
- BULLMQ_REDIS_URL=${BULLMQ_REDIS_URL:-redis://redis:6379/0}
- DATABASE_URL=${DATABASE_URL:-}
depends_on:
redis:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:9102/healthz || exit 1"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
worker-import:
<<: *worker-base
environment:
- WORKER_ENABLED=${WORKER_ENABLED:-false}
- WORKER_QUEUE_GROUP=import
- WORKER_CONCURRENCY_IMPORT=${WORKER_CONCURRENCY_IMPORT:-1}
- WORKER_HEALTH_PORT=9103
- WORKER_ADMIN_PORT=9203
- BULLMQ_REDIS_URL=${BULLMQ_REDIS_URL:-redis://redis:6379/0}
- DATABASE_URL=${DATABASE_URL:-}
depends_on:
redis:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:9103/healthz || exit 1"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
worker-webhook:
<<: *worker-base
environment:
- WORKER_ENABLED=${WORKER_ENABLED:-false}
- WORKER_QUEUE_GROUP=webhook
- WORKER_CONCURRENCY_WEBHOOK=${WORKER_CONCURRENCY_WEBHOOK:-20}
- WORKER_HEALTH_PORT=9104
- WORKER_ADMIN_PORT=9204
- BULLMQ_REDIS_URL=${BULLMQ_REDIS_URL:-redis://redis:6379/0}
- DATABASE_URL=${DATABASE_URL:-}
depends_on:
redis:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:9104/healthz || exit 1"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
worker-plugin:
<<: *worker-base
environment:
- WORKER_ENABLED=${WORKER_ENABLED:-false}
- WORKER_QUEUE_GROUP=plugin
- WORKER_CONCURRENCY_PLUGIN=${WORKER_CONCURRENCY_PLUGIN:-5}
- WORKER_HEALTH_PORT=9105
- WORKER_ADMIN_PORT=9205
- BULLMQ_REDIS_URL=${BULLMQ_REDIS_URL:-redis://redis:6379/0}
- DATABASE_URL=${DATABASE_URL:-}
depends_on:
redis:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:9105/healthz || exit 1"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
# Meilisearch — full-text search engine consumed by packages/search.
# Indexing is driven asynchronously by the worker-general service via
# outbox events; tenant isolation is enforced inside the wrapper. The
# master key is dev-only (`devkey`); production must inject a rotated
# secret. See docs/deploy/meilisearch.md.
meilisearch:
image: getmeili/meilisearch:v1.8
environment:
- MEILI_MASTER_KEY=${MEILI_MASTER_KEY:-devkey}
- MEILI_ENV=${MEILI_ENV:-development}
- MEILI_NO_ANALYTICS=true
ports:
# Bind to loopback only: the default master key is the well-known `devkey`,
# so the search engine must never be reachable from the LAN/host network.
# Production injects a rotated MEILI_MASTER_KEY via its own compose/secrets.
- "127.0.0.1:7700:7700"
volumes:
- meilisearch-data:/meili_data
healthcheck:
test: ["CMD-SHELL", "wget -q -O - http://127.0.0.1:7700/health | grep -q 'available'"]
interval: 10s
timeout: 5s
retries: 6
start_period: 15s
restart: unless-stopped
# Hocuspocus — realtime-collaboration WebSocket server backing the
# Novel-Editor (Y.js CRDT). Auth is JWT-signed via HOCUSPOCUS_AUTH_SECRET
# (issued by the web app's collab-token endpoint). Disabled by default —
# set HOCUSPOCUS_ENABLED=true in `.env` to opt in. See
# docs/features/realtime-collab.md.
hocuspocus:
build:
context: .
dockerfile: apps/hocuspocus/Dockerfile
target: hocuspocus
environment:
- NODE_ENV=${NODE_ENV:-production}
- HOCUSPOCUS_PORT=1234
- HOCUSPOCUS_HOST=0.0.0.0
- HOCUSPOCUS_AUTH_SECRET=${HOCUSPOCUS_AUTH_SECRET:-}
- DATABASE_URL=${DATABASE_URL:-}
- DIRECT_URL=${DIRECT_URL:-}
ports:
- "1234:1234"
profiles:
- realtime
healthcheck:
test:
- "CMD-SHELL"
- "node -e \"require('net').connect(1234,'127.0.0.1').on('connect',()=>process.exit(0)).on('error',()=>process.exit(1))\""
interval: 30s
timeout: 5s
retries: 3
start_period: 15s
restart: unless-stopped
volumes:
clamav-db:
meilisearch-data: