From e64e064306218f32188c84235916488907ca29c9 Mon Sep 17 00:00:00 2001 From: dongsk Date: Tue, 1 Sep 2026 19:15:57 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=B4=E7=90=86docker?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 55 +----------------- mcp-auth/backend/docker-compose.yml | 28 ++++++++++ mcp-auth/frontend/docker-compose.yml | 15 +++++ mcp-auth/src/seed.py | 83 ++-------------------------- 4 files changed, 50 insertions(+), 131 deletions(-) create mode 100644 mcp-auth/backend/docker-compose.yml create mode 100644 mcp-auth/frontend/docker-compose.yml diff --git a/docker-compose.yml b/docker-compose.yml index 3066650..9f96fa9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,17 +1,9 @@ -# 汽车零部件智能报价 — 两个 MCP 服务 + 鉴权管理后台 编排 +# 汽车零部件智能报价 — MCP 服务编排 # 生产环境:docker compose up -d -# 默认连生产库 10.100.154.100:5432,对外 10.100.154.100:8001/8002/8003/8902 +# 默认连生产库 10.100.154.100:5432 # 8001 = mcp-for-erp, 8002 = mcp-for-crm -# 8003 = mcp-auth-backend(FastAPI 纯 API) -# 8902 = mcp-auth-frontend(Nginx 托管 React 静态文件,/api 反代 8003) -# 开发环境:本机直接 python server.py(不入容器) -# source .env.dev 后到 mcp-for-{erp,crm}/src 执行 python server.py -# 连开发库 47.101.220.40:5432,对外 localhost:8001/8002/8000 -# 也可用 docker 跑开发:docker compose --env-file .env.dev up -d # 停止:docker compose down # 日志:docker compose logs -f -# 网络模式 host:容器直接共享宿主网络栈,绕开 Docker 桥接 FORWARD 链, -# 便于局域网其他机器直接访问(无需 ports 映射) services: mcp-for-erp: build: @@ -28,10 +20,7 @@ services: - ERP_DB_USER=${ERP_DB_USER:-postgres} - ERP_DB_PASSWORD=${ERP_DB_PASSWORD:-digiwin} - ERP_DB_NAME=${ERP_DB_NAME:-smart_quotation_auto} - # 对外地址(用于 OAuth 资源元数据),按实际部署机 IP 调整 - MCP_PUBLIC_URL=${MCP_PUBLIC_URL_ERP:-http://10.100.154.100:8001} - # 鉴权(调用 mcp-auth 后端 API 校验,不直连鉴权库) - # per-service API Key:由 mcp-auth 后端签发,各服务独立 - MCP_AUTH_API_URL=${MCP_AUTH_API_URL:-http://10.100.154.100:8003} - MCP_AUTH_API_KEY=${ERP_MCP_AUTH_API_KEY:-change-me-erp-key} restart: unless-stopped @@ -51,47 +40,7 @@ services: - CRM_DB_USER=${CRM_DB_USER:-postgres} - CRM_DB_PASSWORD=${CRM_DB_PASSWORD:-digiwin} - CRM_DB_NAME=${CRM_DB_NAME:-smart_quotation_auto} - # 对外地址(用于 OAuth 资源元数据),按实际部署机 IP 调整 - MCP_PUBLIC_URL=${MCP_PUBLIC_URL_CRM:-http://10.100.154.100:8002} - # 鉴权(调用 mcp-auth 后端 API 校验,不直连鉴权库) - # per-service API Key:由 mcp-auth 后端签发,各服务独立 - MCP_AUTH_API_URL=${MCP_AUTH_API_URL:-http://10.100.154.100:8003} - MCP_AUTH_API_KEY=${CRM_MCP_AUTH_API_KEY:-change-me-crm-key} restart: unless-stopped - - # MCP Auth Backend — FastAPI 纯 API 服务(端口 8003) - mcp-auth-backend: - build: - context: ./mcp-auth/backend - dockerfile: Dockerfile - image: mcp-auth-backend:latest - container_name: mcp-auth-backend - network_mode: host - environment: - - AUTH_DB_HOST=${AUTH_DB_HOST:-10.100.154.100} - - AUTH_DB_PORT=${AUTH_DB_PORT:-5432} - - AUTH_DB_USER=${AUTH_DB_USER:-postgres} - - AUTH_DB_PASSWORD=${AUTH_DB_PASSWORD:-digiwin} - - AUTH_DB_NAME=${AUTH_DB_NAME:-mcp_auth} - # 鼎捷云 IAM 鉴权配置 - - IAM_BASE_URL=${IAM_BASE_URL:-https://iam.digiwincloud.com.cn} - - IAM_APP_TOKEN=${IAM_APP_TOKEN:-eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6ImRhdGEtYnVzaW5lc3MtZGVtbyIsInNpZCI6MH0.Spo64LstbWxjYNefVFAbEbgfjzZoQGNcqKSGuYUOCRk} - - IAM_CACHE_TTL=${IAM_CACHE_TTL:-30} - # Redis 缓存配置 - - REDIS_HOST=${REDIS_HOST:-10.100.154.100} - - REDIS_PORT=${REDIS_PORT:-6379} - - REDIS_DB=${REDIS_DB:-0} - - REDIS_PASSWORD=${REDIS_PASSWORD:-digiwin} - restart: unless-stopped - - # MCP Auth Frontend — Nginx 托管 React 静态文件,/api 反代后端 8003(端口 8902) - mcp-auth-frontend: - build: - context: ./mcp-auth/frontend - dockerfile: Dockerfile - image: mcp-auth-frontend:latest - container_name: mcp-auth-frontend - network_mode: host - environment: - - BACKEND_URL=${BACKEND_URL:-http://10.100.154.100:8003} - restart: unless-stopped diff --git a/mcp-auth/backend/docker-compose.yml b/mcp-auth/backend/docker-compose.yml new file mode 100644 index 0000000..6619f47 --- /dev/null +++ b/mcp-auth/backend/docker-compose.yml @@ -0,0 +1,28 @@ +# MCP Auth Backend — FastAPI 纯 API 服务(端口 8003) +# 启动:docker compose up -d +# 停止:docker compose down +# 日志:docker compose logs -f +services: + mcp-auth-backend: + build: + context: . + dockerfile: Dockerfile + image: mcp-auth-backend:latest + container_name: mcp-auth-backend + network_mode: host + environment: + - AUTH_DB_HOST=${AUTH_DB_HOST:-10.100.154.100} + - AUTH_DB_PORT=${AUTH_DB_PORT:-5432} + - AUTH_DB_USER=${AUTH_DB_USER:-postgres} + - AUTH_DB_PASSWORD=${AUTH_DB_PASSWORD:-digiwin} + - AUTH_DB_NAME=${AUTH_DB_NAME:-mcp_auth} + # 鼎捷云 IAM 鉴权配置 + - IAM_BASE_URL=${IAM_BASE_URL:-https://iam.digiwincloud.com.cn} + - IAM_APP_TOKEN=${IAM_APP_TOKEN:-eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6ImRhdGEtYnVzaW5lc3MtZGVtbyIsInNpZCI6MH0.Spo64LstbWxjYNefVFAbEbgfjzZoQGNcqKSGuYUOCRk} + - IAM_CACHE_TTL=${IAM_CACHE_TTL:-30} + # Redis 缓存配置 + - REDIS_HOST=${REDIS_HOST:-10.100.154.100} + - REDIS_PORT=${REDIS_PORT:-6379} + - REDIS_DB=${REDIS_DB:-0} + - REDIS_PASSWORD=${REDIS_PASSWORD:-digiwin} + restart: unless-stopped diff --git a/mcp-auth/frontend/docker-compose.yml b/mcp-auth/frontend/docker-compose.yml new file mode 100644 index 0000000..8e37978 --- /dev/null +++ b/mcp-auth/frontend/docker-compose.yml @@ -0,0 +1,15 @@ +# MCP Auth Frontend — Nginx 托管 React 静态文件,/api 反代后端 8003(端口 8902) +# 启动:docker compose up -d +# 停止:docker compose down +# 日志:docker compose logs -f +services: + mcp-auth-frontend: + build: + context: . + dockerfile: Dockerfile + image: mcp-auth-frontend:latest + container_name: mcp-auth-frontend + network_mode: host + environment: + - BACKEND_URL=${BACKEND_URL:-http://10.100.154.100:8003} + restart: unless-stopped diff --git a/mcp-auth/src/seed.py b/mcp-auth/src/seed.py index 92a9fd4..ac5a748 100644 --- a/mcp-auth/src/seed.py +++ b/mcp-auth/src/seed.py @@ -1,4 +1,4 @@ -"""初始化 mcp_auth 库 + 灌入现有静态 token + 注册 MCP 服务(一次性迁移脚本)。 +"""初始化 mcp_auth 库 + 建表(一次性脚本)。 用法: # 开发库(47.101.220.40) @@ -7,39 +7,21 @@ # 生产库(10.100.154.100) python seed.py --host 10.100.154.100 --user postgres --password digiwin -幂等:可重复执行,已存在的 token / service 跳过。 +幂等:可重复执行,表已存在则跳过。 """ import argparse import asyncio -import hashlib import os -import secrets from pathlib import Path import asyncpg -# 现有静态 token → (client_id, service_scope, description) -# 与 docker-compose.yml 历史配置一致,迁移后可从 compose 删除 -STATIC_TOKENS = [ - ("erp-token-trae-2026", "trae", "both", "Trae IDE 客户端(跨 ERP+CRM)"), - ("erp-token-partner-a", "partner-a", "erp", "合作伙伴 A(仅 ERP)"), - ("crm-token-trae-2026", "trae", "both", "Trae IDE 客户端(跨 ERP+CRM)"), - ("crm-token-partner-a", "partner-a", "crm", "合作伙伴 A(仅 CRM)"), - ("dev-token-trae", "trae", "both", "开发环境共用 token"), -] - -# MCP 服务初始注册:service_name → description -INITIAL_SERVICES = [ - ("erp", "ERP 数据服务(汽车零部件智能报价)"), - ("crm", "CRM 数据服务(汽车零部件智能报价)"), -] - INIT_SQL_PATH = Path(__file__).resolve().parent.parent / "sql" / "init.sql" async def main() -> None: - parser = argparse.ArgumentParser(description="初始化 mcp_auth 库并迁移静态 token + 注册服务") + parser = argparse.ArgumentParser(description="初始化 mcp_auth 库并建表") parser.add_argument("--host", default=os.getenv("MCP_AUTH_DB_HOST", "127.0.0.1")) parser.add_argument("--port", type=int, default=int(os.getenv("MCP_AUTH_DB_PORT", "5432"))) parser.add_argument("--user", default=os.getenv("MCP_AUTH_DB_USER", "postgres")) @@ -65,65 +47,10 @@ async def main() -> None: ) init_sql = INIT_SQL_PATH.read_text(encoding="utf-8") await conn.execute(init_sql) - print(f"[建表] mcp_token / mcp_token_log / admin_user / mcp_service 已就绪") - - # 3. 灌入静态 token(幂等:token_hash 已存在则跳过) - inserted = 0 - skipped = 0 - for token, client_id, scope, desc in STATIC_TOKENS: - token_hash = hashlib.sha256(token.encode()).hexdigest() - token_prefix = token[:12] + "…" - result = await conn.execute( - """INSERT INTO mcp_token (token_hash, token_prefix, client_id, service_scope, status, description, created_by) - VALUES ($1, $2, $3, $4, 'active', $5, 'seed.py') - ON CONFLICT (token_hash) DO NOTHING""", - token_hash, token_prefix, client_id, scope, desc, - ) - if result.endswith("1"): - inserted += 1 - else: - skipped += 1 - print(f"[迁移] 静态 token:新增 {inserted} 条,跳过 {skipped} 条(已存在)") - - # 4. 注册 MCP 服务 + 生成 per-service API Key(幂等:已存在则跳过) - print(f"[服务] 注册 MCP 服务:") - for service_name, desc in INITIAL_SERVICES: - existing = await conn.fetchrow( - "SELECT service_id FROM mcp_service WHERE service_name = $1 AND status = 'active'", - service_name, - ) - if existing: - print(f" {service_name}: 已存在,跳过") - continue - plain_key = secrets.token_urlsafe(32) - key_hash = hashlib.sha256(plain_key.encode()).hexdigest() - await conn.execute( - """INSERT INTO mcp_service (service_name, api_key, api_key_hash, description, created_by) - VALUES ($1, $2, $3, $4, 'seed.py')""", - service_name, plain_key, key_hash, desc, - ) - print(f" {service_name}: API Key = {plain_key}") - print(f" → 配置到 MCP 服务的 MCP_AUTH_API_KEY 环境变量") - - # 5. 列出当前 token 概览 - rows = await conn.fetch( - "SELECT token_prefix, client_id, service_scope, status FROM mcp_token ORDER BY token_id" - ) - print(f"\n[概览] mcp_token 表共 {len(rows)} 条:") - for r in rows: - print(f" {r['token_prefix']:<16} client={r['client_id']:<12} scope={r['service_scope']:<6} status={r['status']}") - - svc_rows = await conn.fetch( - "SELECT service_name, api_key, status FROM mcp_service ORDER BY service_id" - ) - print(f"\n[概览] mcp_service 表共 {len(svc_rows)} 条:") - for r in svc_rows: - print(f" {r['service_name']:<8} api_key={r['api_key']:<44} status={r['status']}") - + print("[建表] mcp_token / mcp_token_log / admin_user / mcp_service 已就绪") await conn.close() - print("\n[完成] MCP 服务 API Key 仅在本次输出,请立即保存到 .env.dev") - + print("\n[完成] 数据库初始化完毕,种子数据请通过管理后台操作") if __name__ == "__main__":