From 47f61587afea9c2940cb684fddec22e0f4f85a30 Mon Sep 17 00:00:00 2001 From: dongsk Date: Tue, 1 Sep 2026 18:52:04 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=89=93=E5=8C=85=E9=83=A8?= =?UTF-8?q?=E7=BD=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 44 +++++++++++++------- mcp-auth/Dockerfile | 31 -------------- mcp-auth/backend/Dockerfile | 18 +++++++++ mcp-auth/backend/app/core/config.py | 4 +- mcp-auth/frontend/.dockerignore | 7 ++++ mcp-auth/frontend/Dockerfile | 32 +++++++++++++++ mcp-auth/frontend/nginx.conf | 63 +++++++++++++++++++++++++++++ mcp-auth/src/seed.py | 4 +- mcp-for-crm/README.md | 2 +- mcp-for-crm/src/db.py | 2 +- mcp-for-erp/README.md | 2 +- mcp-for-erp/src/db.py | 2 +- 12 files changed, 157 insertions(+), 54 deletions(-) delete mode 100644 mcp-auth/Dockerfile create mode 100644 mcp-auth/backend/Dockerfile create mode 100644 mcp-auth/frontend/.dockerignore create mode 100644 mcp-auth/frontend/Dockerfile create mode 100644 mcp-auth/frontend/nginx.conf diff --git a/docker-compose.yml b/docker-compose.yml index c9478b7..3066650 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,9 @@ # 汽车零部件智能报价 — 两个 MCP 服务 + 鉴权管理后台 编排 # 生产环境:docker compose up -d -# 默认连生产库 192.168.1.206:5432,对外 192.168.1.119:8001/8002/8000 -# 8000 = mcp-auth-admin 管理后台(FastAPI + React) +# 默认连生产库 10.100.154.100:5432,对外 10.100.154.100:8001/8002/8003/8902 +# 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 @@ -21,16 +23,16 @@ services: container_name: mcp-for-erp network_mode: host environment: - - ERP_DB_HOST=${ERP_DB_HOST:-192.168.1.206} + - ERP_DB_HOST=${ERP_DB_HOST:-10.100.154.100} - ERP_DB_PORT=${ERP_DB_PORT:-5432} - 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://192.168.1.119:8001} + - 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://192.168.1.119:8000} + - 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 @@ -44,29 +46,29 @@ services: container_name: mcp-for-crm network_mode: host environment: - - CRM_DB_HOST=${CRM_DB_HOST:-192.168.1.206} + - CRM_DB_HOST=${CRM_DB_HOST:-10.100.154.100} - CRM_DB_PORT=${CRM_DB_PORT:-5432} - 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://192.168.1.119:8002} + - 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://192.168.1.119:8000} + - 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 Admin — Bearer Token 动态鉴权管理后台(FastAPI + React) - mcp-auth-admin: + # MCP Auth Backend — FastAPI 纯 API 服务(端口 8003) + mcp-auth-backend: build: - context: ./mcp-auth + context: ./mcp-auth/backend dockerfile: Dockerfile - image: mcp-auth-admin:latest - container_name: mcp-auth-admin + image: mcp-auth-backend:latest + container_name: mcp-auth-backend network_mode: host environment: - - AUTH_DB_HOST=${AUTH_DB_HOST:-192.168.1.206} + - 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} @@ -76,8 +78,20 @@ services: - IAM_APP_TOKEN=${IAM_APP_TOKEN:-eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6ImRhdGEtYnVzaW5lc3MtZGVtbyIsInNpZCI6MH0.Spo64LstbWxjYNefVFAbEbgfjzZoQGNcqKSGuYUOCRk} - IAM_CACHE_TTL=${IAM_CACHE_TTL:-30} # Redis 缓存配置 - - REDIS_HOST=${REDIS_HOST:-127.0.0.1} + - 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/Dockerfile b/mcp-auth/Dockerfile deleted file mode 100644 index a745120..0000000 --- a/mcp-auth/Dockerfile +++ /dev/null @@ -1,31 +0,0 @@ -# syntax=docker/dockerfile:1 -# MCP Auth Admin — 多阶段构建 -# 阶段1:Node 构建 React 前端 → 阶段2:Python 运行 FastAPI + 托管静态文件 - -# ---- 阶段1:构建前端 ---- -FROM node:20-alpine AS frontend-build -WORKDIR /app/frontend -COPY frontend/package*.json ./ -RUN npm ci -COPY frontend/ ./ -RUN npm run build - -# ---- 阶段2:Python 运行时 ---- -FROM python:3.12-slim -WORKDIR /app - -# 依赖单独成层,利用缓存 -COPY backend/requirements.txt ./requirements.txt -RUN pip install --no-cache-dir -r requirements.txt - -# 后端源码 -COPY backend/app ./app - -# 前端构建产物 -COPY --from=frontend-build /app/frontend/dist ./app/static - -WORKDIR /app -EXPOSE 9000 -# STATIC_DIR 指向后端 app/static(相对 backend 启动目录) -ENV STATIC_DIR=/app/app/static -CMD ["python", "-m", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "9000"] diff --git a/mcp-auth/backend/Dockerfile b/mcp-auth/backend/Dockerfile new file mode 100644 index 0000000..b40bd4e --- /dev/null +++ b/mcp-auth/backend/Dockerfile @@ -0,0 +1,18 @@ +# syntax=docker/dockerfile:1 +# MCP Auth Admin — 后端(FastAPI,纯 API 服务,不托管前端静态文件) + +FROM python:3.12-slim +WORKDIR /app + +# 依赖单独成层,利用缓存 +COPY requirements.txt ./requirements.txt +RUN pip install --no-cache-dir -r requirements.txt + +# 后端源码 +COPY app ./app + +WORKDIR /app +EXPOSE 8003 + +# 不挂载前端静态文件,纯 API 服务 +CMD ["python", "-m", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8003"] diff --git a/mcp-auth/backend/app/core/config.py b/mcp-auth/backend/app/core/config.py index 5e93fd1..2d93158 100644 --- a/mcp-auth/backend/app/core/config.py +++ b/mcp-auth/backend/app/core/config.py @@ -4,7 +4,7 @@ import os class Settings: - AUTH_DB_HOST: str = os.getenv("AUTH_DB_HOST", "47.101.220.40") + AUTH_DB_HOST: str = os.getenv("AUTH_DB_HOST", "10.100.154.100") AUTH_DB_PORT: int = int(os.getenv("AUTH_DB_PORT", "5432")) AUTH_DB_USER: str = os.getenv("AUTH_DB_USER", "postgres") AUTH_DB_PASSWORD: str = os.getenv("AUTH_DB_PASSWORD", "digiwin") @@ -24,7 +24,7 @@ class Settings: STATIC_DIR: str = os.getenv("STATIC_DIR", "../frontend/dist") # Redis 配置 - REDIS_HOST: str = os.getenv("REDIS_HOST", "47.101.220.40") + REDIS_HOST: str = os.getenv("REDIS_HOST", "10.100.154.100") REDIS_PORT: int = int(os.getenv("REDIS_PORT", "6379")) REDIS_DB: int = int(os.getenv("REDIS_DB", "0")) REDIS_PASSWORD: str = os.getenv("REDIS_PASSWORD", "digiwin") diff --git a/mcp-auth/frontend/.dockerignore b/mcp-auth/frontend/.dockerignore new file mode 100644 index 0000000..317c734 --- /dev/null +++ b/mcp-auth/frontend/.dockerignore @@ -0,0 +1,7 @@ +node_modules +dist +.git +.gitignore +*.md +.vscode +.idea diff --git a/mcp-auth/frontend/Dockerfile b/mcp-auth/frontend/Dockerfile new file mode 100644 index 0000000..6ce0bee --- /dev/null +++ b/mcp-auth/frontend/Dockerfile @@ -0,0 +1,32 @@ +# ── Stage 1: Build ────────────────────────────────── +FROM node:20-alpine AS builder + +WORKDIR /app + +# 先复制依赖描述文件,利用 Docker 缓存层 +COPY package.json package-lock.json* ./ + +# 安装依赖 +RUN npm install + +# 复制源码 +COPY . . + +# 构建生产包(tsc + vite build → dist/) +RUN npm run build + +# ── Stage 2: Serve ────────────────────────────────── +FROM nginx:alpine + +# 将构建产物复制到 Nginx 默认静态目录 +COPY --from=builder /app/dist /usr/share/nginx/html + +# Nginx 配置模板(支持 envsubst 环境变量替换) +COPY nginx.conf /etc/nginx/templates/default.conf.template + +# 默认后端 API 地址(运行时可通过 -e BACKEND_URL=... 覆盖) +ENV BACKEND_URL=http://10.100.154.100:8003 + +EXPOSE 8902 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/mcp-auth/frontend/nginx.conf b/mcp-auth/frontend/nginx.conf new file mode 100644 index 0000000..58cb37a --- /dev/null +++ b/mcp-auth/frontend/nginx.conf @@ -0,0 +1,63 @@ +server { + listen 8902; + server_name localhost; + + root /usr/share/nginx/html; + index index.html; + + # gzip 压缩 + gzip on; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml text/javascript image/svg+xml; + gzip_min_length 256; + + # 后端 API 反向代理 + location /api/ { + proxy_pass ${BACKEND_URL}/api/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # 禁止浏览器缓存 API 响应 + add_header Cache-Control "no-cache, no-store, must-revalidate" always; + add_header Pragma "no-cache" always; + } + + # 健康检查 + location /health { + proxy_pass ${BACKEND_URL}/api/health; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } + + # 鼎捷云 IAM 登录服务反向代理(与 vite.config.ts 中 /iam-api 代理一致) + location /iam-api/ { + proxy_pass https://iam.digiwincloud.com.cn/; + proxy_set_header Host iam.digiwincloud.com.cn; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_ssl_server_name on; + + # 禁止浏览器缓存 API 响应 + add_header Cache-Control "no-cache, no-store, must-revalidate" always; + add_header Pragma "no-cache" always; + } + + # SPA 路由 fallback:所有非文件请求回退到 index.html + location / { + try_files $uri $uri/ /index.html; + } + + # 静态资源长缓存(Vite 构建产物带 hash) + location /assets/ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # SVG / 图片缓存 + location ~* \.(svg|png|jpg|jpeg|gif|ico|webp)$ { + expires 30d; + add_header Cache-Control "public"; + } +} diff --git a/mcp-auth/src/seed.py b/mcp-auth/src/seed.py index 68283d4..92a9fd4 100644 --- a/mcp-auth/src/seed.py +++ b/mcp-auth/src/seed.py @@ -4,8 +4,8 @@ # 开发库(47.101.220.40) python seed.py --host 47.101.220.40 --user postgres --password digiwin - # 生产库(192.168.1.206) - python seed.py --host 192.168.1.206 --user postgres --password digiwin + # 生产库(10.100.154.100) + python seed.py --host 10.100.154.100 --user postgres --password digiwin 幂等:可重复执行,已存在的 token / service 跳过。 """ diff --git a/mcp-for-crm/README.md b/mcp-for-crm/README.md index baa28ce..8e88b4b 100644 --- a/mcp-for-crm/README.md +++ b/mcp-for-crm/README.md @@ -42,7 +42,7 @@ python server.py # 启动 MCP Server(端口 8002) | 变量 | 默认值 | 说明 | |---|---|---| -| `CRM_DB_HOST` | 192.168.1.206 | PostgreSQL 主机 | +| `CRM_DB_HOST` | 10.100.154.100 | PostgreSQL 主机 | | `CRM_DB_PORT` | 5432 | 端口 | | `CRM_DB_USER` | postgres | 用户名 | | `CRM_DB_PASSWORD` | digiwin | 密码 | diff --git a/mcp-for-crm/src/db.py b/mcp-for-crm/src/db.py index 66253d6..dbfa236 100644 --- a/mcp-for-crm/src/db.py +++ b/mcp-for-crm/src/db.py @@ -4,7 +4,7 @@ import asyncpg import os DB_CONFIG = { - "host": os.getenv("CRM_DB_HOST", "192.168.1.206"), + "host": os.getenv("CRM_DB_HOST", "10.100.154.100"), "port": int(os.getenv("CRM_DB_PORT", "5432")), "user": os.getenv("CRM_DB_USER", "postgres"), "password": os.getenv("CRM_DB_PASSWORD", "digiwin"), diff --git a/mcp-for-erp/README.md b/mcp-for-erp/README.md index aa6d585..ed1891d 100644 --- a/mcp-for-erp/README.md +++ b/mcp-for-erp/README.md @@ -53,7 +53,7 @@ python server.py # 启动 MCP Server(端口 8001) | 变量 | 默认值 | 说明 | |---|---|---| -| `ERP_DB_HOST` | 192.168.1.206 | PostgreSQL 主机 | +| `ERP_DB_HOST` | 10.100.154.100 | PostgreSQL 主机 | | `ERP_DB_PORT` | 5432 | 端口 | | `ERP_DB_USER` | postgres | 用户名 | | `ERP_DB_PASSWORD` | digiwin | 密码 | diff --git a/mcp-for-erp/src/db.py b/mcp-for-erp/src/db.py index dadbecf..d7ef0f4 100644 --- a/mcp-for-erp/src/db.py +++ b/mcp-for-erp/src/db.py @@ -4,7 +4,7 @@ import asyncpg import os DB_CONFIG = { - "host": os.getenv("ERP_DB_HOST", "192.168.1.206"), + "host": os.getenv("ERP_DB_HOST", "10.100.154.100"), "port": int(os.getenv("ERP_DB_PORT", "5432")), "user": os.getenv("ERP_DB_USER", "postgres"), "password": os.getenv("ERP_DB_PASSWORD", "digiwin"),