Files
hunjing/docker/docker-compose.app.yml
T
chenxin 144415247e M4 收口:神识用户面与计量闭环——BYOK/配额三段式/usage 落库/Anthropic+Gemini 适配器/神识阁
- 神识 Go:store 双实现(PG 自动建表+60s 就绪重试 / 内存回退)承载 usage_logs·byok_keys·quota_balances;BYOK 密钥库(AES-GCM 加密、API 脱敏、撤回即失效、主密钥未配置 fail-closed);配额三段式(预扣 max_tokens 钳位 1M→结算实际 token→全败幂等退款,HJ-2004);计量归属(IR user_id→usage_logs,/me/usage 用户维度聚合+配额总览,/admin/usage/sample 对账抽样);Anthropic/Gemini 出站适配器(SSE 解析、system 提升、用量映射);stub 端点补名修复计量空 endpoint
- IR 契约:user_id/byok_key_id 双端同步(Go types.go + Py types.py)
- 灵台:runs.owner_id(迁移 005,server_default 兼容存量)经 kernel 全链透传为 IR user_id;shenshi_client 扩展用户面方法(X-Hunjing-User-Id 代理,Echo 桩带内存实现);/me/byok-keys 登记·列表·撤回与 /me/usage 端点(4 用例)
- 前端神识阁(/models 重建):偏好(生成参数表单)/自带密钥(登记加密保存、脱敏列表、撤回二次确认)/用量(聚合表+配额进度条)三区;me API 库+mock+5 用例;侧栏恢复入口
- 配置与部署:.env.example 增 SHENSHI_DATABASE_URL/SHENSHI_BYOK_MASTER_KEY/SHENSHI_USER_BUDGET_TOKENS;compose 神识容器接自有库(init-shenshi.sql 预建 hunjing_shenshi,与灵台不共库共表)
- 证据:Go 34 用例(BYOK 独占/配额拒绝/结算退款/归属聚合)、后端 532、前端 210、BFF 4 全绿;跨进程 E2E 四场景(灵台 HttpShenshiClient→真 Go 神识:登记脱敏/BYOK 独占不可达整体失败/用量归属聚合/撤回即失效)通过;rewrite-plan M4 标记完成、能力矩阵神识行升已验证
2026-08-27 18:39:17 +08:00

285 lines
12 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ==============================
# 魂镜应用层编排(后端 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 M4) ==============================
# 灵台唯一模型出口:IR 入站 → 适配器(openai_compatible/anthropic/gemini/local/stub)→ SSE 出站。
# 计量/BYOK/配额:SHENSHI_DATABASE_URL 指向独立库(与灵台不共库共表,需在 PG 预建
# hunjing_shenshi database;未配置时进程内存储,重启即失)。
# 鉴权: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"
SHENSHI_DATABASE_URL: postgresql://hunjing:${POSTGRES_PASSWORD:-change-me}@hunjing-postgres:5432/hunjing_shenshi
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 }