# ============================== # 魂镜应用层编排(后端 FastAPI + 前端 Next.js)。 # 与基础设施 docker-compose.infra.yml 解耦:本文件以 external 方式引用共享网络 hunjing-net, # 通过服务名(hunjing-postgres / hunjing-redis / hunjing-milvus / hunjing-neo4j / hunjing-nebula-graphd)连接基础设施。 # # 前置:先启动基础设施以创建 hunjing-net 网络与所需数据库等: # docker compose -f docker/docker-compose.infra.yml up -d # # 常用命令: # # 启动前后端(会构建镜像) # docker compose -f docker/docker-compose.app.yml up -d --build # # 仅启动后端 / 前端 # docker compose -f docker/docker-compose.app.yml up -d hunjing-backend # docker compose -f docker/docker-compose.app.yml up -d hunjing-frontend # # 查看日志 # docker compose -f docker/docker-compose.app.yml logs -f hunjing-backend # # 停止 # docker compose -f docker/docker-compose.app.yml down # # 内存限制:每个服务通过 deploy.resources.limits/reservations 约束内存,可按宿主机规格调整。 # ============================== name: hunjing networks: hunjing-net: external: true name: hunjing-net # 沙箱专属内部网络:internal=true 禁止公网出站,仅同网络容器互访。 # 后端通过此网络访问沙箱;沙箱不接入 hunjing-net,彻底切断其公网出口,防数据外泄。 sandbox-net: internal: true name: hunjing-sandbox-net services: # ============================== 灵台 · 后端 FastAPI(Backend) ============================== hunjing-backend: build: context: .. dockerfile: docker/backend/Dockerfile image: hunjing-backend:latest container_name: hunjing-backend restart: unless-stopped networks: [hunjing-net, sandbox-net] # 注入根目录 .env(含模型密钥等);缺失时启动会报错,请先 `cp .env.example .env`。 env_file: - ../.env environment: # 覆盖容器网络服务发现地址(优先级高于 env_file),保持 .env 中 127.0.0.1 默认值不变。 APP_ENV: production DATABASE_TYPE: pgsql POSTGRES_HOST: hunjing-postgres POSTGRES_PORT: "5432" REDIS_HOST: hunjing-redis MILVUS_HOST: hunjing-milvus NEO4J_URI: bolt://hunjing-neo4j:7687 NEBULAGRAPH_HOST: hunjing-nebula-graphd MINIO_ENDPOINT: http://hunjing-minio:9000 STORAGE_PROVIDER: ${STORAGE_PROVIDER:-local} # rewrite/1.0:模型出口走神识网关(覆盖 .env 默认空值;令牌经 env_file 注入) SHENSHI_BASE_URL: http://hunjing-shenshi:8080 volumes: # bind mount 到 /app 下的对应目录,使 .env 相对路径 ../logs ../db ../storage ../config 生效。 - ../logs:/app/logs - ../db:/app/db - ../storage:/app/storage - ../config:/app/config:ro ports: - "${BACKEND_PORT:-8000}:8000" # 注意:数据库等基础设施位于 infra 文件,跨文件无法用 depends_on 表达。 # 请先启动 infra;后端自身应有数据库连接重试逻辑以应对基础设施尚未就绪的情况。 deploy: resources: limits: { memory: 1G } reservations: { memory: 256M } # ============================== 神识 · 模型网关(Go,rewrite/1.0 M0) ============================== # 灵台唯一模型出口:IR 入站 → 适配器(当前 stub,云 Provider/元炁按 M4 接入)→ SSE 出站。 # 鉴权:SHENSHI_SERVICE_TOKEN 经 env_file 注入;未配置时开发档放行。 hunjing-shenshi: build: context: ../shenshi dockerfile: ../docker/shenshi/Dockerfile image: hunjing-shenshi:latest container_name: hunjing-shenshi restart: unless-stopped networks: [hunjing-net] env_file: - ../.env environment: SHENSHI_PORT: "8080" deploy: resources: limits: { memory: 256M } reservations: { memory: 64M } # ============================== 照壁 · BFF(Fastify,rewrite/1.0 M0) ============================== # 客户端与灵台之间的无状态通道:鉴权透传、SSE 直通、响应透传。无业务规则、无权威数据。 hunjing-bff: build: context: ../bff dockerfile: ../docker/bff/Dockerfile image: hunjing-bff:latest container_name: hunjing-bff restart: unless-stopped networks: [hunjing-net] environment: BFF_PORT: "3000" BACKEND_URL: http://hunjing-backend:8000 depends_on: hunjing-backend: condition: service_started deploy: resources: limits: { memory: 256M } reservations: { memory: 64M } # ============================== 琉璃镜 · 前端 Next.js(Frontend) ============================== hunjing-frontend: build: context: .. dockerfile: docker/frontend/Dockerfile image: hunjing-frontend:latest container_name: hunjing-frontend restart: unless-stopped networks: [hunjing-net] environment: NODE_ENV: production # 容器内 Next 服务端(BFF)通过容器网络服务名连后端;浏览器只同源访问前端, # 所有请求经 BFF(/api/proxy、/api/sse、/api/auth),不需要后端地址。 BACKEND_URL: http://hunjing-backend:8000 ports: - "${FRONTEND_PORT:-3000}:3000" depends_on: hunjing-backend: condition: service_started deploy: resources: limits: { memory: 512M } reservations: { memory: 128M } # ============================== 乾坤 · 安全沙箱(可选,profile: sandbox,Rust 微服务 / Sandbox Engine) ============================== # 为百工 Tool Runtime 提供本地隔离的命令执行层(POST /v1/exec,GET /healthz)。详见 sandbox/README.md。 # 启用:docker compose -f docker/docker-compose.app.yml --profile sandbox up -d --build hunjing-sandbox # # 容器级隔离加固(沙箱进程内另有进程组 / 超时 / 输出截断 / 路径逃逸拒绝,见 sandbox/README.md): # - 网络:仅接入 internal 的 sandbox-net,无公网出站;后端通过该网络以服务名 hunjing-sandbox 访问。 # - 资源:pids_limit 防 fork bomb、cpus+memory 限额防 CPU/内存耗尽、/tmp 走 tmpfs 限大小防磁盘写满。 # - 权限:read-only 根、no-new-privileges、cap_drop ALL、默认 seccomp profile(最小权限)。 # - 更强隔离(自定义 seccomp 白名单 / nsjail·gVisor·microVM)见 sandbox/README.md「后续加固」。 hunjing-sandbox: build: context: .. dockerfile: docker/sandbox/Dockerfile image: hunjing-sandbox:latest container_name: hunjing-sandbox profiles: ["sandbox"] restart: unless-stopped networks: [sandbox-net] # 注入根目录 .env(与 backend 一致)。compose 的 ${} 插值不查找项目根 .env(插值源是 # compose 文件所在目录 docker/.env,不存在),故 SANDBOX_AUTH_SECRET 必须经 env_file 注入 # 容器;environment 块不重设它以免覆盖。executor 另有 env_clear + allowed_env 白名单 # (仅 PATH/HOME/TZ/LANG),被执行的子进程拿不到本环境里的其他敏感变量。 env_file: - ../.env environment: SANDBOX_HOST: 0.0.0.0 SANDBOX_PORT: "8090" SANDBOX_BASE_WORKDIR: /app/sandbox-work SANDBOX_LOG_DIR: /app/logs SANDBOX_MAX_TIMEOUT_MS: ${SANDBOX_MAX_TIMEOUT_MS:-30000} SANDBOX_MAX_CONCURRENT: ${SANDBOX_MAX_CONCURRENT:-8} SANDBOX_MAX_OUTPUT_BYTES: ${SANDBOX_MAX_OUTPUT_BYTES:-1048576} SANDBOX_ALLOWED_ENV: ${SANDBOX_ALLOWED_ENV:-PATH,HOME,TZ,LANG} SANDBOX_AUTH_ENABLED: ${SANDBOX_AUTH_ENABLED:-true} RUST_LOG: ${RUST_LOG:-info} volumes: # 持久化沙箱工作目录到项目根 sandbox-work/(已加入 .gitignore) - ../sandbox-work:/app/sandbox-work # 日志写到项目根 logs/sandbox.log(与后端 app.log 同目录,便于统一查看/收集) - ../logs:/app/logs # /tmp 走 tmpfs(64M),限制临时文件占用,防止写满磁盘 tmpfs: - /tmp:size=67108864,mode=1777 # 最小权限加固:只读根文件系统(仅 /tmp tmpfs 与 sandbox-work bind mount 可写)、 # 禁止子进程提权(no-new-privileges)、丢弃所有 capabilities(kill 进程组属同 UID 操作无需 cap)。 # seccomp 用 Docker 默认 profile。 read_only: true security_opt: - no-new-privileges:true cap_drop: - ALL ports: - "${SANDBOX_PORT:-8090}:8090" # 进程数与 CPU 限额:防 fork bomb 与 CPU 耗尽(pids/cpus 随 deploy.resources 在非 swarm 下生效) deploy: resources: limits: { memory: 512M, cpus: "1.0", pids: 256 } reservations: { memory: 64M } # ============================== 元炁 · 本地推理引擎(可选,profile: yuanqi,Local Inference Engine) ============================== # 纯 Python 本地推理引擎,提供 LLM / Embedding / Reranker / 多模态推理能力。 # 所有模型文件存放在项目根目录 models/ 下,容器启动时挂载到 /app/models。 # 启用:docker compose -f docker/docker-compose.app.yml --profile yuanqi up -d --build hunjing-yuanqi hunjing-yuanqi: build: context: .. dockerfile: docker/yuanqi/Dockerfile image: hunjing-yuanqi:latest container_name: hunjing-yuanqi profiles: ['yuanqi'] restart: unless-stopped networks: [hunjing-net] environment: YUANQI_HOST: 0.0.0.0 YUANQI_PORT: '11434' YUANQI_MODELS_DIR: /app/models YUANQI_DEVICE: ${YUANQI_DEVICE:-auto} YUANQI_LOG_LEVEL: ${YUANQI_LOG_LEVEL:-info} volumes: - ../models:/app/models:ro - ../logs:/app/logs ports: - '${YUANQI_PORT:-11434}:11434' deploy: resources: limits: { memory: 4G } reservations: { memory: 1G } # ============================== 天目 · 本地 OCR 引擎(可选,profile: tianmu) ============================== # 本地 OCR 推理引擎,提供 PP-OCRv6 快速文字提取 + PaddleOCR-VL-1.6 复杂文档解析。 # 所有模型文件存放在项目根目录 models/ 下,容器启动时挂载到 /app/models。 # 启用:docker compose -f docker/docker-compose.app.yml --profile tianmu up -d --build hunjing-tianmu hunjing-tianmu: build: context: .. dockerfile: docker/tianmu/Dockerfile image: hunjing-tianmu:latest container_name: hunjing-tianmu profiles: ['tianmu'] restart: unless-stopped networks: [hunjing-net] environment: TIANMU_HOST: '0.0.0.0' TIANMU_PORT: '8101' TIANMU_MODELS_DIR: /app/models TIANMU_DEVICE: ${TIANMU_DEVICE:-auto} TIANMU_LOG_LEVEL: ${TIANMU_LOG_LEVEL:-info} volumes: - ../models:/app/models:ro - ../logs:/app/logs ports: - '${TIANMU_PORT:-8101}:8101' deploy: resources: limits: { memory: 4G } reservations: { memory: 1G } # ============================== 天门 · 反向代理(Nginx,可选,profile: nginx,统一入口) ============================== # 对外只暴露 80:/api/* 与 SSE 走后端,其余走前端。配置见 docker/nginx/nginx.conf。 # 启用:docker compose -f docker/docker-compose.app.yml --profile nginx up -d hunjing-nginx hunjing-nginx: image: nginx:1.27-alpine container_name: hunjing-nginx profiles: ["nginx"] restart: unless-stopped networks: [hunjing-net] volumes: - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro ports: - "${NGINX_PORT:-80}:80" depends_on: hunjing-backend: condition: service_started hunjing-bff: condition: service_started hunjing-frontend: condition: service_started deploy: resources: limits: { memory: 128M } reservations: { memory: 32M }