services: # ────────────────────────────────────────── # 1. MySQL 主数据库 # ────────────────────────────────────────── mysql: image: mysql:8.0 container_name: ws-mysql restart: unless-stopped environment: TZ: ${TZ:-Asia/Shanghai} MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-root_pass_change_me} MYSQL_DATABASE: ${MYSQL_DATABASE:-wenshu_platform} MYSQL_USER: ${MYSQL_USER:-wenshu} MYSQL_PASSWORD: ${MYSQL_PASSWORD:-wenshu_db_pass} volumes: - ./data/mysql:/var/lib/mysql - ./backend/src/main/resources/db/schema.sql:/docker-entrypoint-initdb.d/01-schema.sql:ro ports: - "3306:3306" healthcheck: test: ["CMD-SHELL", "mysqladmin ping -h localhost -u$${MYSQL_USER} -p$${MYSQL_PASSWORD} --silent"] interval: 10s timeout: 5s retries: 10 # ────────────────────────────────────────── # 2. Milvus 向量数据库(依赖 etcd + minio) # ────────────────────────────────────────── milvus-etcd: image: quay.io/coreos/etcd:v3.5.18 container_name: ws-milvus-etcd restart: unless-stopped environment: ETCD_AUTO_COMPACTION_MODE: revision ETCD_AUTO_COMPACTION_RETENTION: "1000" ETCD_QUOTA_BACKEND_BYTES: "4294967296" ETCD_SNAPSHOT_COUNT: "50000" volumes: - ./data/milvus/etcd:/etcd command: > etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls=http://0.0.0.0:2379 --data-dir=/etcd healthcheck: test: ["CMD", "etcdctl", "endpoint", "health"] interval: 30s timeout: 20s retries: 3 milvus-minio: image: minio/minio:RELEASE.2023-03-20T20-16-18Z container_name: ws-milvus-minio restart: unless-stopped environment: MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY:-minioadmin} MINIO_SECRET_KEY: ${MINIO_SECRET_KEY:-minioadmin} volumes: - ./data/milvus/minio:/minio_data command: minio server /minio_data --console-address ":9001" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] interval: 30s timeout: 20s retries: 3 milvus-standalone: image: milvusdb/milvus:v2.4.15 container_name: ws-milvus-standalone restart: unless-stopped depends_on: milvus-etcd: condition: service_healthy milvus-minio: condition: service_healthy environment: ETCD_ENDPOINTS: milvus-etcd:2379 MINIO_ADDRESS: milvus-minio:9000 volumes: - ./data/milvus/milvus:/var/lib/milvus ports: - "19530:19530" - "9091:9091" command: ["milvus", "run", "standalone"] healthcheck: test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"] interval: 30s timeout: 20s retries: 5 # ────────────────────────────────────────── # 3. Apache Polaris(Iceberg REST Catalog) # 依赖专属 Postgres # ────────────────────────────────────────── polaris-postgres: image: postgres:16 container_name: ws-polaris-postgres restart: unless-stopped environment: TZ: ${TZ:-Asia/Shanghai} POSTGRES_DB: ${POLARIS_POSTGRES_DB:-polaris} POSTGRES_USER: ${POLARIS_POSTGRES_USER:-polaris} POSTGRES_PASSWORD: ${POLARIS_POSTGRES_PASSWORD:-polaris_pg_pass} volumes: - ./data/polaris/postgres:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] interval: 10s timeout: 5s retries: 10 polaris: image: apache/polaris:1.3.0-incubating container_name: ws-polaris restart: unless-stopped depends_on: polaris-postgres: condition: service_healthy ports: - "8181:8181" environment: POLARIS_PERSISTENCE_TYPE: relational-jdbc DROP_WITH_PURGE_ENABLED: ${POLARIS_DROP_WITH_PURGE_ENABLED:-true} QUARKUS_DATASOURCE_USERNAME: ${POLARIS_POSTGRES_USER:-polaris} QUARKUS_DATASOURCE_PASSWORD: ${POLARIS_POSTGRES_PASSWORD:-polaris_pg_pass} QUARKUS_DATASOURCE_JDBC_URL: jdbc:postgresql://polaris-postgres:5432/${POLARIS_POSTGRES_DB:-polaris} QUARKUS_HTTP_PORT: 8181 AWS_ACCESS_KEY_ID: ${OSS_AK:-} AWS_SECRET_ACCESS_KEY: ${OSS_SK:-} AWS_REGION: ${OSS_REGION:-cn-hangzhou} AWS_DEFAULT_REGION: ${OSS_REGION:-cn-hangzhou} AWS_REQUEST_CHECKSUM_CALCULATION: WHEN_REQUIRED AWS_RESPONSE_CHECKSUM_VALIDATION: WHEN_REQUIRED healthcheck: test: ["CMD-SHELL", "bash -c '/dev/null && exit 0 || exit 1"] interval: 15s timeout: 5s retries: 20 start_period: 60s # ────────────────────────────────────────── # 4. TEI 向量化服务(CPU 模式) # ────────────────────────────────────────── tei: image: ghcr.io/huggingface/text-embeddings-inference:cpu-latest container_name: ws-tei restart: unless-stopped volumes: - ./data/huggingface:/data ports: - "7997:80" command: ["--model-id", "${TEI_MODEL_ID:-intfloat/multilingual-e5-base}"] healthcheck: test: ["CMD", "curl", "-sf", "http://localhost:80/health"] interval: 30s timeout: 10s retries: 10 start_period: 120s # 首次下载模型需要时间 # ────────────────────────────────────────── # 5. Spring Boot 后端 # ────────────────────────────────────────── backend: build: context: ./backend dockerfile: Dockerfile container_name: ws-backend restart: unless-stopped environment: TZ: ${TZ:-Asia/Shanghai} MYSQL_URL: ${MYSQL_URL:-mysql:3306} MYSQL_DATABASE: ${MYSQL_DATABASE:-wenshu_platform} MYSQL_USER: ${MYSQL_USER:-wenshu} MYSQL_PASSWORD: ${MYSQL_PASSWORD:-wenshu_db_pass} STOCK_SSH_CRYPTO_KEY: ${STOCK_SSH_CRYPTO_KEY:-change-me-stock-ssh-key-32chars} SERVER_IP: ${SERVER_IP:-} POLARIS_HOST: ${POLARIS_HOST:-} POLARIS_REALM: ${POLARIS_REALM:-POLARIS} POLARIS_CLIENT_ID: ${POLARIS_CLIENT_ID:-root} POLARIS_CLIENT_SECRET: ${POLARIS_CLIENT_SECRET:-s3cr3t} POLARIS_DEFAULT_CATALOG: ${POLARIS_DEFAULT_CATALOG:-demo_catalog} POLARIS_CACHE_TTL_MINUTES: ${POLARIS_CACHE_TTL_MINUTES:-10} KUBEADM_JOIN_COMMAND: ${KUBEADM_JOIN_COMMAND:-} OSS_ENDPOINT: ${OSS_ENDPOINT:-https://oss-cn-hangzhou.aliyuncs.com} OSS_AK: ${OSS_AK:-} OSS_SK: ${OSS_SK:-} OSS_REGION: ${OSS_REGION:-cn-hangzhou} OSS_BUCKET: ${OSS_BUCKET:-} ICEBERG_SERVICE_URL: ${ICEBERG_SERVICE_URL:-http://python-iceberg:8090} K8S_ORCHESTRATOR_BASE_URL: ${K8S_ORCHESTRATOR_BASE_URL:-http://ws-orchestrator-api:8080} K8S_ORCHESTRATOR_TIMEOUT_MS: ${K8S_ORCHESTRATOR_TIMEOUT_MS:-5000} K8S_ORCHESTRATOR_WAIT_TIMEOUT_MS: ${K8S_ORCHESTRATOR_WAIT_TIMEOUT_MS:-300000} K8S_ORCHESTRATOR_POLL_INTERVAL_MS: ${K8S_ORCHESTRATOR_POLL_INTERVAL_MS:-2000} K8S_ORCHESTRATOR_RECONCILE_CREATE_DELAY_MS: ${K8S_ORCHESTRATOR_RECONCILE_CREATE_DELAY_MS:-5000} K8S_ORCHESTRATOR_RECONCILE_BATCH_SIZE: ${K8S_ORCHESTRATOR_RECONCILE_BATCH_SIZE:-100} BACKEND_INTERNAL_HEADER: ${BACKEND_INTERNAL_HEADER:-X-Internal-Token} BACKEND_INTERNAL_TOKEN: ${BACKEND_INTERNAL_TOKEN:-change-me-internal-token} STARROCKS_SQL_RUNNER_USERNAME: ${STARROCKS_SQL_RUNNER_USERNAME:-root} STARROCKS_SQL_RUNNER_PASSWORD: ${STARROCKS_SQL_RUNNER_PASSWORD:-} STARROCKS_SQL_RUNNER_POLARIS_CATALOG: ${STARROCKS_SQL_RUNNER_POLARIS_CATALOG:-polaris} STARROCKS_SQL_RUNNER_QUERY_PORT: ${STARROCKS_SQL_RUNNER_QUERY_PORT:-9030} RAG_EMBEDDING_DIMENSION: ${RAG_EMBEDDING_DIMENSION:-768} RAG_EMBEDDING_URL: ${RAG_EMBEDDING_URL:-http://tei:80/v1} RAG_EMBEDDING_MODEL: ${RAG_EMBEDDING_MODEL:-intfloat/multilingual-e5-base} RAG_MILVUS_URI: ${RAG_MILVUS_URI:-http://milvus-standalone:19530} RAG_MILVUS_COLLECTION: ${RAG_MILVUS_COLLECTION:-knowledge_vectors} RAG_RETRIEVAL_TOP_K: ${RAG_RETRIEVAL_TOP_K:-8} RAG_RETRIEVAL_SCORE_THRESHOLD: ${RAG_RETRIEVAL_SCORE_THRESHOLD:-0.3} extra_hosts: - "host.docker.internal:host-gateway" volumes: - ./backend/config:/app/config depends_on: mysql: condition: service_healthy milvus-standalone: condition: service_healthy ports: - "8080:8080" healthcheck: test: ["CMD-SHELL", "bash -c '/dev/null && exit 0 || exit 1"] interval: 15s timeout: 5s retries: 20 start_period: 90s # ────────────────────────────────────────── # 6. Python Iceberg 服务 # 启动时会调用 backend 获取配置,必须在 backend 之后启动 # ────────────────────────────────────────── python-iceberg: build: context: ./python-iceberg dockerfile: Dockerfile container_name: ws-python-iceberg restart: unless-stopped depends_on: backend: condition: service_healthy polaris: condition: service_healthy ports: - "8090:8090" environment: BACKEND_URL: ${ICEBERG_BACKEND_URL:-http://backend:8080} BACKEND_INTERNAL_HEADER: ${BACKEND_INTERNAL_HEADER:-X-Internal-Token} BACKEND_INTERNAL_TOKEN: ${BACKEND_INTERNAL_TOKEN:-change-me-internal-token} # ────────────────────────────────────────── # 7. 前端(Nginx) # ────────────────────────────────────────── frontend: build: context: ./frontend dockerfile: Dockerfile container_name: ws-frontend restart: unless-stopped depends_on: - backend ports: - "80:80" # ────────────────────────────────────────── # 8. k8s-orchestrator(默认启动,需可访问 K8s API) # ────────────────────────────────────────── ws-orchestrator-api: build: context: ./k8s-orchestrator dockerfile: Dockerfile.api container_name: ws-orchestrator-api restart: unless-stopped user: "0:0" environment: TZ: ${TZ:-Asia/Shanghai} API_BIND_ADDRESS: ":8080" SECRET_NAMESPACE: ${K8S_ORCHESTRATOR_SECRET_NAMESPACE:-orchestrator-system} KUBECONFIG: /kube/config volumes: - ${K8S_KUBECONFIG_PATH:-/root/.kube/config}:/kube/config:ro ports: - "18080:8080" ws-orchestrator-controller: build: context: ./k8s-orchestrator dockerfile: Dockerfile.controller container_name: ws-orchestrator-controller restart: unless-stopped user: "0:0" command: ["--leader-elect=false"] environment: TZ: ${TZ:-Asia/Shanghai} KUBECONFIG: /kube/config SERVER_IP: ${SERVER_IP:-} KUBEADM_JOIN_COMMAND: ${KUBEADM_JOIN_COMMAND:-} STARROCKS_BOOTSTRAP_POLARIS_ENABLED: ${STARROCKS_BOOTSTRAP_POLARIS_ENABLED:-true} POLARIS_HOST: ${POLARIS_HOST:-} POLARIS_CLIENT_ID: ${POLARIS_CLIENT_ID:-root} POLARIS_CLIENT_SECRET: ${POLARIS_CLIENT_SECRET:-s3cr3t} POLARIS_CATALOG_NAME: ${POLARIS_CATALOG_NAME:-polaris} POLARIS_CATALOG_WAREHOUSE: ${POLARIS_CATALOG_WAREHOUSE:-demo_catalog} POLARIS_CATALOG_DROP_WITH_PURGE_ENABLED: ${POLARIS_CATALOG_DROP_WITH_PURGE_ENABLED:-true} POLARIS_CATALOG_OAUTH2_CREDENTIAL: ${POLARIS_CATALOG_OAUTH2_CREDENTIAL:-} POLARIS_CATALOG_OAUTH2_SCOPE: ${POLARIS_CATALOG_OAUTH2_SCOPE:-PRINCIPAL_ROLE:ALL} POLARIS_CATALOG_VENDED_CREDENTIALS_ENABLED: ${POLARIS_CATALOG_VENDED_CREDENTIALS_ENABLED:-false} STARROCKS_BOOTSTRAP_STORAGE_REGION: ${STARROCKS_BOOTSTRAP_STORAGE_REGION:-${OSS_REGION:-}} STARROCKS_BOOTSTRAP_STORAGE_ENDPOINT: ${STARROCKS_BOOTSTRAP_STORAGE_ENDPOINT:-${OSS_ENDPOINT:-}} STARROCKS_BOOTSTRAP_STORAGE_ACCESS_KEY: ${STARROCKS_BOOTSTRAP_STORAGE_ACCESS_KEY:-${OSS_AK:-}} STARROCKS_BOOTSTRAP_STORAGE_SECRET_KEY: ${STARROCKS_BOOTSTRAP_STORAGE_SECRET_KEY:-${OSS_SK:-}} STARROCKS_BOOTSTRAP_STORAGE_PATH_STYLE_ACCESS: ${STARROCKS_BOOTSTRAP_STORAGE_PATH_STYLE_ACCESS:-false} volumes: - ${K8S_KUBECONFIG_PATH:-/root/.kube/config}:/kube/config:ro