# BrainAPI production profile: heavy (Neo4j + MongoDB + Milvus + Redis). x-brainapi-common: &brainapi-common image: ${BRAINAPI_IMAGE:?BRAINAPI_IMAGE is required} env_file: - ${BRAINAPI_ENV_FILE:?BRAINAPI_ENV_FILE is required} environment: &brainapi-environment ENV: production PLUGIN_FAILURE_POLICY: ${PLUGIN_FAILURE_POLICY:-fail} REDIS_HOST: redis REDIS_PORT: "6379" REDIS_PASSWORD: ${REDIS_PASSWORD:?REDIS_PASSWORD is required} NEO4J_HOST: neo4j NEO4J_PORT: "7687" NEO4J_USERNAME: ${NEO4J_USERNAME:-neo4j} NEO4J_PASSWORD: ${NEO4J_PASSWORD:?NEO4J_PASSWORD is required} MONGO_HOST: mongo MONGO_PORT: "27017" MONGO_USERNAME: ${MONGO_USERNAME:-brainapi} MONGO_PASSWORD: ${MONGO_PASSWORD:?MONGO_PASSWORD is required} MONGO_SYSTEM_DATABASE: ${MONGO_SYSTEM_DATABASE:-system} MILVUS_HOST: milvus MILVUS_PORT: "19530" MILVUS_TOKEN: ${MILVUS_TOKEN:?MILVUS_TOKEN is required} BRAINAPI_PLUGINS: ${BRAINAPI_PLUGINS:-} PLUGIN_REGISTRY_URL: ${PLUGIN_REGISTRY_URL:-} PLUGIN_PUBLISHER_ID: ${PLUGIN_PUBLISHER_ID:-} PLUGIN_PUBLISHER_API_KEY: ${PLUGIN_PUBLISHER_API_KEY:-} volumes: [brainapi-plugins:/app/plugins] networks: [appnet] restart: unless-stopped services: nginx: image: nginx:1.28.2-alpine3.23 ports: ["80:80", "443:443"] volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro - ./nginx/conf.d:/etc/nginx/conf.d:ro depends_on: brainapi: {condition: service_healthy} brainapi-mcp: {condition: service_healthy} networks: [appnet] restart: unless-stopped read_only: true tmpfs: [/var/cache/nginx, /var/run, /tmp] security_opt: [no-new-privileges:true] mem_limit: 128m cpus: 0.20 healthcheck: test: ["CMD", "wget", "-q", "--spider", "http://localhost/health"] interval: 15s timeout: 5s retries: 5 redis: image: redis:7.4.7-alpine3.21 environment: REDIS_PASSWORD: ${REDIS_PASSWORD:?REDIS_PASSWORD is required} command: [redis-server, --requirepass, "${REDIS_PASSWORD:?REDIS_PASSWORD is required}", --appendonly, "yes", --maxmemory, 1500mb, --maxmemory-policy, allkeys-lru, --save, "900 1", --save, "300 10", --save, "60 10000"] volumes: [redis-data:/data] networks: [appnet] restart: unless-stopped security_opt: [no-new-privileges:true] mem_limit: 2g cpus: 0.50 healthcheck: test: ["CMD-SHELL", "redis-cli -a \"$${REDIS_PASSWORD}\" ping 2>/dev/null | grep -q PONG"] interval: 10s timeout: 3s retries: 5 neo4j: image: neo4j:5.26.16-enterprise environment: NEO4J_AUTH: ${NEO4J_USERNAME:-neo4j}/${NEO4J_PASSWORD:?NEO4J_PASSWORD is required} NEO4J_ACCEPT_LICENSE_AGREEMENT: "yes" NEO4J_PLUGINS: '["apoc"]' NEO4J_server_memory_heap_max__size: 2g NEO4J_server_memory_pagecache_size: 1g volumes: - neo4j-data:/data - neo4j-logs:/logs - neo4j-plugins:/plugins networks: [appnet] restart: unless-stopped security_opt: [no-new-privileges:true] mem_limit: 3g cpus: 1.0 healthcheck: test: ["CMD-SHELL", "cypher-shell -u \"$${NEO4J_AUTH%%/*}\" -p \"$${NEO4J_AUTH#*/}\" 'RETURN 1' >/dev/null"] interval: 15s timeout: 10s retries: 10 start_period: 90s etcd: image: quay.io/coreos/etcd:v3.5.18 environment: ETCD_AUTO_COMPACTION_MODE: revision ETCD_AUTO_COMPACTION_RETENTION: "1000" ETCD_QUOTA_BACKEND_BYTES: "4294967296" ETCD_SNAPSHOT_COUNT: "50000" command: [etcd, --advertise-client-urls=http://etcd:2379, --listen-client-urls=http://0.0.0.0:2379, --data-dir=/etcd] volumes: [etcd-data:/etcd] networks: [appnet] restart: unless-stopped security_opt: [no-new-privileges:true] mem_limit: 512m cpus: 0.25 healthcheck: test: ["CMD", "etcdctl", "endpoint", "health"] interval: 15s timeout: 10s retries: 5 minio: image: minio/minio:RELEASE.2024-12-18T13-15-44Z environment: MINIO_ROOT_USER: ${MINIO_ACCESS_KEY:?MINIO_ACCESS_KEY is required} MINIO_ROOT_PASSWORD: ${MINIO_SECRET_KEY:?MINIO_SECRET_KEY is required} command: [minio, server, /minio_data, --console-address, ":9001"] volumes: [minio-data:/minio_data] networks: [appnet] restart: unless-stopped security_opt: [no-new-privileges:true] mem_limit: 1g cpus: 0.40 healthcheck: test: ["CMD", "curl", "-fsS", "http://localhost:9000/minio/health/live"] interval: 15s timeout: 10s retries: 5 milvus: image: milvusdb/milvus:v2.6.6 command: [milvus, run, standalone] security_opt: [seccomp:unconfined, no-new-privileges:true] environment: ETCD_ENDPOINTS: etcd:2379 MINIO_ADDRESS: minio:9000 MINIO_ACCESS_KEY_ID: ${MINIO_ACCESS_KEY:?MINIO_ACCESS_KEY is required} MINIO_SECRET_ACCESS_KEY: ${MINIO_SECRET_KEY:?MINIO_SECRET_KEY is required} COMMON_SECURITY_AUTHORIZATION_ENABLED: "true" COMMON_SECURITY_DEFAULT_ROOT_PASSWORD: ${MILVUS_ROOT_PASSWORD:?MILVUS_ROOT_PASSWORD is required} MQ_TYPE: woodpecker MILVUS_COMMON_LOG_LEVEL: warn volumes: [milvus-data:/var/lib/milvus] networks: [appnet] depends_on: etcd: {condition: service_healthy} minio: {condition: service_healthy} restart: unless-stopped mem_limit: 2g cpus: 0.75 healthcheck: test: ["CMD", "curl", "-fsS", "http://localhost:9091/healthz"] interval: 20s timeout: 10s retries: 6 start_period: 60s mongo: image: mongo:8.0.16-noble environment: MONGO_INITDB_ROOT_USERNAME: ${MONGO_USERNAME:-brainapi} MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASSWORD:?MONGO_PASSWORD is required} command: [mongod, --wiredTigerCacheSizeGB=1, --bind_ip_all] volumes: - mongo-data:/data/db - mongo-config:/data/configdb networks: [appnet] restart: unless-stopped security_opt: [no-new-privileges:true] mem_limit: 2g cpus: 0.50 healthcheck: test: ["CMD-SHELL", "mongosh --quiet --username \"$${MONGO_INITDB_ROOT_USERNAME}\" --password \"$${MONGO_INITDB_ROOT_PASSWORD}\" --authenticationDatabase admin --eval 'quit(db.adminCommand({ping:1}).ok ? 0 : 2)'"] interval: 10s timeout: 5s retries: 10 brainapi: <<: *brainapi-common command: [-m, uvicorn, src.services.api.app:app, --host, 0.0.0.0, --port, "8000", --workers, "1", --timeout-keep-alive, "30", --limit-concurrency, "200"] depends_on: redis: {condition: service_healthy} neo4j: {condition: service_healthy} mongo: {condition: service_healthy} milvus: {condition: service_healthy} mem_limit: 4g cpus: 2.0 security_opt: [no-new-privileges:true] healthcheck: test: ["CMD", "curl", "-fsS", "http://localhost:8000/health"] interval: 20s timeout: 5s retries: 12 start_period: 120s brainapi-worker: <<: *brainapi-common command: [-m, celery, -A, src.workers.app, worker, --loglevel=info, --pool=threads, --without-gossip, --without-mingle, --concurrency=2, --max-tasks-per-child=50] depends_on: redis: {condition: service_healthy} neo4j: {condition: service_healthy} mongo: {condition: service_healthy} milvus: {condition: service_healthy} mem_limit: 4g cpus: 2.0 security_opt: [no-new-privileges:true] healthcheck: test: - CMD-SHELL - >- python -m celery -A src.workers.app inspect ping --timeout 5 >/dev/null 2>&1 && python -c 'import os,redis,sys; r=redis.Redis(host="redis",password=os.environ["REDIS_PASSWORD"]); sys.exit(r.llen("ingest_data") >= int(os.getenv("CELERY_QUEUE_HEALTH_THRESHOLD","50")))' interval: 30s timeout: 10s retries: 5 start_period: 120s brainapi-mcp: <<: *brainapi-common environment: <<: *brainapi-environment MCP_OAUTH_ISSUER_URL: ${MCP_OAUTH_ISSUER_URL:-} MCP_RESOURCE_SERVER_URL: ${MCP_RESOURCE_SERVER_URL:-} command: [-m, uvicorn, src.services.mcp.app:app, --host, 0.0.0.0, --port, "8001", --timeout-keep-alive, "30"] depends_on: redis: {condition: service_healthy} neo4j: {condition: service_healthy} mongo: {condition: service_healthy} milvus: {condition: service_healthy} mem_limit: 2g cpus: 1.0 security_opt: [no-new-privileges:true] healthcheck: test: ["CMD", "curl", "-fsS", "http://localhost:8001/"] interval: 20s timeout: 5s retries: 5 start_period: 60s networks: appnet: driver: bridge volumes: redis-data: neo4j-data: neo4j-logs: neo4j-plugins: etcd-data: minio-data: milvus-data: mongo-data: mongo-config: brainapi-plugins: