name: zm-rag

# Bind-mount 版本：所有持久化数据映射到宿主机 ./volumes/ 目录
# 数据目录结构：
#   docker/volumes/
#   ├── opensearch/data/      — OpenSearch 索引数据
#   ├── neo4j/data/           — Neo4j 图数据库
#   ├── neo4j/logs/           — Neo4j 日志
#   └── redis/data/           — Redis AOF 持久化
#
# 首次启动前需创建目录并赋权：
#   mkdir -p volumes/opensearch/data volumes/neo4j/data volumes/neo4j/logs volumes/redis/data
#   chmod 777 volumes/opensearch/data
#   chmod 777 volumes/neo4j/data volumes/neo4j/logs
#   chmod 777 volumes/redis/data

services:
  opensearch:
    build:
      context: ./opensearch
      dockerfile: Dockerfile
    container_name: zm-rag-opensearch
    environment:
      # JVM heap
      - OPENSEARCH_JAVA_OPTS=-Xms4g -Xmx4g
      # Cluster
      - cluster.name=zm-rag-cluster
      - node.name=zm-rag-node-1
      - discovery.type=single-node
      # Disable security for internal network
      - plugins.security.disabled=true
      # Network
      - network.host=0.0.0.0
      # Enable kNN plugin
      - knn.plugin.enabled=true
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 65536
        hard: 65536
    volumes:
      - ./volumes/opensearch/data:/usr/share/opensearch/data
      - ./opensearch/analysis:/usr/share/opensearch/config/analysis
      - ./opensearch/opensearch.yml:/usr/share/opensearch/config/opensearch.yml:ro
    ports:
      - "9200:9200"
    networks:
      - zm-rag-net
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "curl -sf http://localhost:9200/_cluster/health | grep -qE '\"status\":\"(green|yellow)\"' || exit 1"]
      interval: 30s
      timeout: 15s
      retries: 10
      start_period: 60s

  opensearch-dashboards:
    image: opensearchproject/opensearch-dashboards:2.19.4
    container_name: zm-rag-dashboards
    depends_on:
      opensearch:
        condition: service_healthy
    environment:
      - OPENSEARCH_HOSTS=["http://opensearch:9200"]
      - DISABLE_SECURITY_DASHBOARDS_PLUGIN=true
    ports:
      - "5601:5601"
    networks:
      - zm-rag-net
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "curl -sf http://localhost:5601/api/status | grep -q 'available' || exit 1"]
      interval: 30s
      timeout: 15s
      retries: 10
      start_period: 120s

  neo4j:
    image: neo4j:5-community
    container_name: zm-rag-neo4j
    environment:
      - NEO4J_AUTH=neo4j/zm_rag_2024
      - NEO4J_PLUGINS=["apoc"]
      - NEO4J_server_memory_heap_initial__size=2g
      - NEO4J_server_memory_heap_max__size=4g
      - NEO4J_server_memory_pagecache_size=2g
      - NEO4J_dbms_security_procedures_unrestricted=apoc.*
      - NEO4J_dbms_security_procedures_allowlist=apoc.*
    volumes:
      - ./volumes/neo4j/data:/data
      - ./volumes/neo4j/logs:/logs
    ports:
      - "7474:7474"
      - "7687:7687"
    networks:
      - zm-rag-net
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "cypher-shell -u neo4j -p zm_rag_2024 'RETURN 1' || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 5
      start_period: 30s

  redis:
    image: redis:alpine
    container_name: zm-rag-redis
    command: redis-server --maxmemory 4gb --maxmemory-policy allkeys-lru --appendonly yes
    volumes:
      - ./volumes/redis/data:/data
    ports:
      - "6379:6379"
    networks:
      - zm-rag-net
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5

networks:
  zm-rag-net:
    driver: bridge
