name: bat services: postgres: image: postgres:17-alpine container_name: bat.postgres restart: unless-stopped mem_limit: 2g memswap_limit: 4g mem_swappiness: 0 environment: POSTGRES_USER: tradeuser POSTGRES_PASSWORD: tradepassword POSTGRES_DB: trading TZ: Asia/Shanghai volumes: - postgres17.data:/var/lib/postgresql/data - ./litellm/01-create-litellm-database.sql:/docker-entrypoint-initdb.d/01-create-litellm-database.sql:ro healthcheck: test: [ "CMD-SHELL", "pg_isready -U tradeuser -d trading" ] interval: 1m start_interval: 10s timeout: 5s retries: 5 start_period: 20s networks: - bat.network redis: image: redis:7-alpine container_name: bat.redis restart: unless-stopped mem_limit: 2g memswap_limit: 4g mem_swappiness: 0 volumes: - redis.data:/data environment: - TZ=Asia/Shanghai healthcheck: test: [ "CMD", "redis-cli", "ping" ] interval: 1m start_interval: 10s timeout: 5s retries: 5 start_period: 20s networks: - bat.network litellm: image: docker.litellm.ai/berriai/litellm-non_root:latest container_name: bat.litellm restart: unless-stopped mem_limit: 2g memswap_limit: 4g mem_swappiness: 0 command: ["--config", "/run/secrets/litellm_config", "--port", "4000"] secrets: - litellm_config depends_on: postgres: condition: service_healthy healthcheck: test: [ "CMD-SHELL", "python -c \"import urllib.request; urllib.request.urlopen('http://127.0.0.1:4000/health/liveliness', timeout=5).read()\"", ] interval: 1m start_interval: 10s timeout: 10s retries: 3 start_period: 40s networks: - bat.network backend: image: ghcr.io/marvekg/bat.backend:latest container_name: bat.backend restart: unless-stopped mem_limit: 2g memswap_limit: 4g mem_swappiness: 0 env_file: - ./backend/.env environment: TZ: Asia/Shanghai extra_hosts: - "host.docker.internal:host-gateway" depends_on: postgres: condition: service_healthy redis: condition: service_healthy sandbox: condition: service_healthy volumes: # - ./backend:/app # FOR DEBUG - backend.runtime.data:/runtime healthcheck: test: [ "CMD", "curl", "-f", "http://127.0.0.1:8000/health" ] interval: 1m start_interval: 10s timeout: 10s retries: 3 start_period: 80s networks: - bat.network sandbox: image: ghcr.io/marvekg/bat.sandbox:latest container_name: bat.sandbox restart: unless-stopped cpus: "4.0" mem_limit: 4g memswap_limit: 6g mem_swappiness: 0 environment: TZ: Asia/Shanghai SANDBOX_RELOAD: "false" SANDBOX_RUNTIME_DIR: /runtime SANDBOX_MAX_CONCURRENT_EXECUTIONS: 4 SANDBOX_WORKER_POOL_SIZE: 4 SANDBOX_WORKER_POOL_MAX_STARTING: 2 SANDBOX_WORKER_ACQUIRE_TIMEOUT_SECONDS: 30 SANDBOX_STARTUP_PREWARM_WORKERS: 1 SANDBOX_PREWARM_POOL_SIZE: 4 SANDBOX_PREWARM_MAX_STARTING: 2 volumes: - sandbox.runtime.data:/runtime healthcheck: test: [ "CMD", "curl", "-f", "http://127.0.0.1:8030/health" ] interval: 1m start_interval: 10s timeout: 10s retries: 3 start_period: 80s networks: - bat.network webfetch: image: ghcr.io/marvekg/bat.webfetch:latest container_name: bat.webfetch restart: unless-stopped cpus: "4.0" mem_limit: 2g memswap_limit: 4g mem_swappiness: 0 environment: TZ: Asia/Shanghai WEBFETCH_MAX_PAGES: 4 WEBFETCH_ENGINE_ACQUIRE_TIMEOUT_MS: 30000 WEBFETCH_RELOAD: "false" WEBFETCH_RUNTIME_DIR: /runtime CLOAKBROWSER_CACHE_DIR: /runtime/cloakbrowser/cache PLAYWRIGHT_BROWSERS_PATH: /runtime/browsers/ms-playwright XDG_CACHE_HOME: /runtime/cache volumes: - webfetch.runtime.data:/runtime healthcheck: test: [ "CMD", "curl", "-f", "http://127.0.0.1:8010/health" ] interval: 1m start_interval: 10s timeout: 10s retries: 3 start_period: 80s networks: - bat.network scrapling.mcp: image: ghcr.io/d4vinci/scrapling:latest container_name: scrapling.mcp restart: unless-stopped command: ["mcp", "--http", "--host", "0.0.0.0", "--port", "8765"] cpus: "4.0" mem_limit: 4g memswap_limit: 6g mem_swappiness: 0 environment: TZ: Asia/Shanghai healthcheck: test: [ "CMD-SHELL", "python -c \"import socket; s=socket.create_connection(('127.0.0.1', 8765), 5); s.close()\"", ] interval: 1m start_interval: 10s timeout: 10s retries: 3 start_period: 80s networks: - bat.network frontend: image: ghcr.io/marvekg/bat.frontend:latest container_name: bat.frontend restart: unless-stopped mem_limit: 2g memswap_limit: 4g mem_swappiness: 0 environment: - NODE_ENV=production - TZ=Asia/Shanghai volumes: # - ./frontend:/app # FOR DEBUG - /app/node_modules healthcheck: test: [ "CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:5173/" ] interval: 1m start_interval: 10s timeout: 10s retries: 3 start_period: 40s networks: - bat.network nginx: image: nginxinc/nginx-unprivileged:alpine container_name: bat.nginx restart: unless-stopped mem_limit: 2g memswap_limit: 4g mem_swappiness: 0 depends_on: backend: condition: service_healthy frontend: condition: service_healthy ports: - "80:8080" # LiteLLM OpenAI-compatible API and Admin UI (/ui), exposed through nginx. - "4000:4000" healthcheck: test: [ "CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:8080/" ] interval: 1m start_interval: 10s timeout: 10s retries: 3 start_period: 40s secrets: - source: nginx_config target: /etc/nginx/conf.d/default.conf environment: - TZ=Asia/Shanghai networks: - bat.network volumes: postgres17.data: name: bat.postgres17.data redis.data: name: bat.redis.data backend.runtime.data: name: bat.backend.runtime.data sandbox.runtime.data: name: bat.sandbox.runtime.data webfetch.runtime.data: name: bat.webfetch.runtime.data secrets: litellm_config: name: bat.litellm.config file: ./litellm/config.yaml nginx_config: name: bat.nginx.config file: ./nginx.conf networks: bat.network: name: bat.network driver: bridge