# geMoldInsight — unified 模式(默认入口) # # 一键启动: # docker compose up -d # # 其他模式(换文件名即可,无需 --profile): # docker compose -f docker-compose.moldinsight.yml up -d # docker compose -f docker-compose.inventory.yml up -d # # 注意:服务均未声明 profiles(compose 规则:声明了 profiles 的服务在 # 不带 --profile 时不会被选中,裸 up 会报 "no service selected"), # 旧 --profile 写法不再是模式开关,模式切换唯一入口是 -f 文件名。 # # 服务清单:frontend + backend(unified 入口) + moldinsight-celery # 镜像:gemold-backend / gemold-frontend(celery 复用 gemold-backend,仅 command 不同) # --------------------------------------------------------------- # 公共环境变量(moldinsight 家族 backend/celery/moldinsight 共用) # 通过 anchor 在本文件内复用,避免 environment 块重复 # --------------------------------------------------------------- x-base-env: &base_env DB_HOST: ${DB_HOST} DB_PORT: ${DB_PORT:-5432} DB_NAME: ${DB_NAME:-moldinsight} DB_USER: ${DB_USER} DB_PASSWORD: ${DB_PASSWORD} REDIS_HOST: ${REDIS_HOST} REDIS_PORT: ${REDIS_PORT:-6379} REDIS_PASSWORD: ${REDIS_PASSWORD:-} RUSTFS_ENDPOINT: ${RUSTFS_ENDPOINT} RUSTFS_ACCESS_KEY: ${RUSTFS_ACCESS_KEY} RUSTFS_SECRET_KEY: ${RUSTFS_SECRET_KEY} RUSTFS_TIMEOUT: ${RUSTFS_TIMEOUT:-30} # SECRET_KEY 必须在 .env 中显式配置,否则 compose 直接失败 SECRET_KEY: ${SECRET_KEY:?SECRET_KEY 未配置:请在 .env 中设置} ALGORITHM: ${ALGORITHM:-HS256} ACCESS_TOKEN_EXPIRE_MINUTES: ${ACCESS_TOKEN_EXPIRE_MINUTES:-1440} DEBUG: ${DEBUG:-false} SERVE_FRONTEND_STATIC: ${SERVE_FRONTEND_STATIC:-false} UPLOAD_DIR: ${UPLOAD_DIR:-./uploads} MAX_FILE_SIZE: ${MAX_FILE_SIZE:-104857600} ALLOWED_EXTENSIONS: ${ALLOWED_EXTENSIONS:-.stp,.step,.stp.gz} POINTCLOUD_SAMPLE_COUNT: ${POINTCLOUD_SAMPLE_COUNT:-10000} MESH_QUALITY: ${MESH_QUALITY:-high} PARALLEL_PROCESSING: ${PARALLEL_PROCESSING:-true} RUSTFS_PRESIGNED_URL_EXPIRES: ${RUSTFS_PRESIGNED_URL_EXPIRES:-3600} ENABLE_FREECAD_VERIFICATION: ${ENABLE_FREECAD_VERIFICATION:-false} FREECAD_VERIFICATION_TIMEOUT: ${FREECAD_VERIFICATION_TIMEOUT:-120} LLM_ENABLED: ${LLM_ENABLED:-false} LLM_API_URL: ${LLM_API_URL:-https://api.openai.com/v1} LLM_API_KEY: ${LLM_API_KEY:-} LLM_MODEL: ${LLM_MODEL:-gpt-4o-mini} LLM_TIMEOUT: ${LLM_TIMEOUT:-60} LLM_MAX_TOKENS: ${LLM_MAX_TOKENS:-2000} services: frontend: build: context: . dockerfile: deploy/Dockerfile.frontend image: gemold-frontend:latest container_name: gemold_frontend ports: # 浏览器入口端口(无默认值:必须由 .env 中 FRONTEND_PORT 显式配置) - "${FRONTEND_PORT}:8000" depends_on: - backend restart: unless-stopped networks: - gemold_network backend: build: context: . dockerfile: deploy/Dockerfile.moldinsight image: gemold-backend:latest container_name: gemold_backend command: ["python", "-m", "uvicorn", "entrypoints.unified:app", "--host", "0.0.0.0", "--port", "8000"] # 宿主机端口由 .env 的 BACKEND_PORT 决定:空/不设则不暴露宿主机端口 # (仅经前端 /api 反代同域访问,避免与 frontend 抢占宿主 10003)。 # 调试时设 BACKEND_PORT=10003 即可独立访问。 ports: - "${BACKEND_PORT:-}:8000" environment: <<: *base_env ADMIN_USERNAME: ${ADMIN_USERNAME:-admin} ADMIN_PASSWORD: ${ADMIN_PASSWORD:?ADMIN_PASSWORD 未配置:请在 .env 中设置} ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@gemold.com} ADMIN_FULL_NAME: ${ADMIN_FULL_NAME:-系统管理员} AUTO_MIGRATE: ${AUTO_MIGRATE:-true} # 共享卷过渡兜底(D6/D11):主链路已改走 RustFS。uploads 供 RustFS 异常时 # 本地路径回退;html_output 仅作 /html 报告代理的存量兜底读(新产物不落本地) volumes: - uploads_data:/app/uploads - html_data:/app/html_output restart: unless-stopped networks: - gemold_network moldinsight-celery: # 与 backend 共用同一镜像(同一 build 声明 + 同一 tag,compose 只构建一次), # 仅以 command 覆盖启动 worker——消除旧 Dockerfile.celery(已删)FROM # gemold-backend 在并行构建下的"镜像尚不存在"陷阱,干净机器裸 up 一把过 build: context: . dockerfile: deploy/Dockerfile.moldinsight image: gemold-backend:latest container_name: gemold_celery # cd /app/src 是必须的:celery_app / celery_tasks 是 src/ 的子模块, # 而其 import 用的是裸模块名(celery_app.py 内 include=["celery_tasks"]), # 所以 worker 必须从 src/ 目录启动;不依赖 celery 版本是否支持 --workdir command: ["sh", "-c", "cd /app/src && exec celery -A celery_app worker --concurrency=${CELERY_CONCURRENCY:-2} --max-tasks-per-child=${CELERY_MAX_TASKS_PER_CHILD:-50} --loglevel=info"] environment: <<: *base_env # Celery/OCC 吞吐调优(OCC_THROUGHPUT 方案 A) CELERY_CONCURRENCY: ${CELERY_CONCURRENCY:-2} CELERY_MAX_TASKS_PER_CHILD: ${CELERY_MAX_TASKS_PER_CHILD:-50} # uploads_data 共享卷(D6 过渡兜底):RustFS 异常时 worker 回退本地路径下载。 # D11 后 worker 不再写 HTML 产物(直传 RustFS 报告键),无需 html_data 卷 volumes: - uploads_data:/app/uploads depends_on: - backend restart: unless-stopped networks: - gemold_network networks: gemold_network: # 固定 name,便于跨 compose 文件调试时容器互通(如 inventory-only 与 unified 临时联调) name: gemold_network driver: bridge volumes: uploads_data: name: gemold_uploads_data html_data: name: gemold_html_data