diff --git a/deploy/bff_restart.sh b/deploy/bff_restart.sh index f19b7e8..59be6d1 100755 --- a/deploy/bff_restart.sh +++ b/deploy/bff_restart.sh @@ -1,13 +1,13 @@ #!/bin/bash # deploy/bff_restart.sh —— 远端 BFF 重启(PM 使用,在远端执行) # 用法:ssh 192.168.0.175 -p 26518 'bash ~/5090/teamWorkspace/zh/PlantAI-rag-new/deploy/bff_restart.sh [bind_addr]' -# 参数:可选绑定地址(默认 0.0.0.0 面向客户内网访问;纯本机调试传 127.0.0.1) +# 参数:可选绑定地址(默认 127.0.0.1——nginx 80 为唯一客户入口,BFF 仅本机;无 nginx 的旧形态可显式传 0.0.0.0) # 要点:用 setsid 完全脱离 SSH 会话,stdout/stderr 全部落日志。 # 2026-09-01 统一 Python:conda plantai-bff → plantai-rag-new-venv(py3.12.13) set -uo pipefail SDK_ROOT="/home/xzq/5090/teamWorkspace/zh/plantai-rag-new-deploy-unified/sdk" PYTHON="/home/xzq/5090/teamWorkspace/zh/plantai-rag-new-venv/bin/python" -BIND="${1:-0.0.0.0}" +BIND="${1:-127.0.0.1}" [[ -x "$PYTHON" ]] || { echo "BFF Python 不可执行: $PYTHON" >&2; exit 1; } # 杀旧进程:按 8090 端口精确匹配(TL 2026-09-06 修—— diff --git a/deploy/nginx/plantai.conf b/deploy/nginx/plantai.conf new file mode 100644 index 0000000..441ce57 --- /dev/null +++ b/deploy/nginx/plantai.conf @@ -0,0 +1,46 @@ +# plantai.conf —— PlantAI-rag-new nginx 反向代理(80 端口唯一客户入口) +# 用法(目标机):cp 本文件到 nginx conf.d(路径因发行版而异,先 nginx -t 看默认 include 路径), +# 然后 nginx -t && systemctl reload nginx(或直接启动)。 +# 约定:本模板反代 127.0.0.1:8090(BFF,自托管 ui/dist 静态 + 全部 API)。 +# 其余内部服务(8091 QA / 8092 methodology / 8093 legacy / 8094 vstore / 8098 bioflow) +# 不对外暴露,nginx 不代理它们。 +# 关键适配(对应系统实际特性,勿删): +# - SSE 流(/api/qa/chat/stream、/api/bioflow/*):buffering 必须 off、长读超时须大于 +# BFF 看门狗 1200s(本配置 3600s)。 +# - 大文件上传(2026-09-04 起无大小限制;生信基因组数百 MB):client_max_body_size 0、 +# 上传缓冲关、send 超时 ≥ BFF 上传超时 600s。 +server { + listen 80; + # server_name 可换成实际域名或内网 IP,如 server_name 192.168.0.175; + server_name _; + + # 上传:不限制大小(上传限制在应用层已移除;生信大文件数百 MB) + client_max_body_size 0; + + location / { + proxy_pass http://127.0.0.1:8090; + + # ---- SSE 长连接适配(问答流/生信流;勿删勿改)---- + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_buffering off; + proxy_cache off; + proxy_read_timeout 3600s; # > BFF SSE 看门狗 1200s + + # ---- 大文件上传适配(勿删勿改)---- + proxy_request_buffering off; + proxy_send_timeout 600s; # ≥ BFF 上传读超时 600s + + # ---- 标准头 ---- + 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; + } + + # 可选优化:对可压缩类型开启 gzip(后端为浏览器静态与 JSON 响应) + gzip on; + gzip_types text/plain text/css application/javascript application/json image/svg+xml; + gzip_proxied any; + gzip_min_length 1024; +} diff --git a/deploy/start-dev.sh b/deploy/start-dev.sh index c1e3345..974b2b2 100644 --- a/deploy/start-dev.sh +++ b/deploy/start-dev.sh @@ -2,9 +2,9 @@ # deploy/start-dev.sh —— 远端启动 BFF + vite dev(在远端 tmux 中运行) set -euo pipefail ROOT="/home/xzq/5090/teamWorkspace/zh/PlantAI-rag-new" -echo "== 启动 BFF (0.0.0.0:8090) ==" +echo "== 启动 BFF (127.0.0.1:8090,经 nginx 80 对外) ==" (cd "$ROOT/sdk" && \ - nohup /home/xzq/5090/teamWorkspace/zh/plantai-rag-new-venv/bin/python -m uvicorn app.main:app --host 0.0.0.0 --port 8090 > /tmp/plantai-bff.log 2>&1 &) + nohup /home/xzq/5090/teamWorkspace/zh/plantai-rag-new-venv/bin/python -m uvicorn app.main:app --host 127.0.0.1 --port 8090 > /tmp/plantai-bff.log 2>&1 &) echo "== 启动 Vite dev (127.0.0.1:5180) ==" (cd "$ROOT/ui" && nohup npm run dev > /tmp/plantai-vite.log 2>&1 &) sleep 3 diff --git a/docs/DEPLOY_FLOW.md b/docs/DEPLOY_FLOW.md index 760a11f..1ec1f70 100644 --- a/docs/DEPLOY_FLOW.md +++ b/docs/DEPLOY_FLOW.md @@ -12,12 +12,13 @@ | 构建机 | ssh -p 26518 xzq@192.168.0.175(内网);仓库 `/home/xzq/5090/teamWorkspace/zh/PlantAI-rag-new`,分支 `feature/bioflow-conversation-orchestration` | | 构建机 Python | 统一 venv `/home/xzq/5090/teamWorkspace/zh/plantai-rag-new-venv/bin/python`(py3.12.13),各编译脚本的 `[python]` 参数一律传它 | | 编译纪律 | 全部 .py → Cython → gcc hidden visibility → strip → elf 校验 → **删除 .py 与 .c 源码**;白名单明文:各树入口 main/api + config + schemas + db + qa.py + sse_relay.py + bioflow_proxy.py + 全部 `__init__.py`(含 yield 的 SSE 模块必须明文,断流崩溃历史教训) | -| 目标机绑定策略 | 8090(客户 UI)绑 `0.0.0.0`;8091/8092/8093/8094/8098/8099 全部 `127.0.0.1` | +| 目标机绑定策略 | **nginx 80 = 唯一客户入口**;8090/8091/8092/8093/8094/8098/8099 全部 `127.0.0.1`(BFF 改绑见 §5b,启动脚本默认已是 127.0.0.1) | | 数据库加密现状 | QA 的 KB 数据(断言 9.5G+2.7G)已具备加密工具链(`tooling/kb/encrypt_kb.sh`,AES-256-GCM + kb.key),但 **`tooling.env` 当前 SKIP_KB=1**(定版前不执行);Qdrant 向量与 Neo4j 冷拷按设计明文(检索数学/存储引擎限制,见 `tooling/KB_ENCRYPT_GUIDE.md`);**KB 解密密钥的运行时消费方尚未实现**(生产实测无 kb.key 引用),此为本手册遗留缺口(见 §7 已知限制) | | 明文残余 | vstore 曾明文部署;已新增 `tooling/compile/compile_vstore.sh`(12 模块 .so + api.py 白名单)并纳入打包流水线;vstore 的 `.env` 含 VSTORE_KEY(Fernet 密文钥匙)不入包 | | 生信内核 | `bioflow_kernel/`(528M)**不参与本流程**——它编译进 8 个 Docker 镜像(镜像内编译),镜像随 build_all 独立分发(`docker save/load`);目标机要生信还需 24 个镜像(8 bioflow-* + 16 plantai-env-*)与 BIOFLOW_DATA 数据根,详见 `docs/bioflow_image_build_playbook.md` | | 打包产物目录 | `tooling/build//install/`(VERSION 默认读 `tooling/tooling.env`,当前 2.0.0) | | 已就绪辅助脚本 | `deploy/ollama_restart.sh`(本地嵌入模型拉起)、`vstore/vstore_restart.sh`(路径自推导重启)已入包 | +| nginx 代理模板 | `deploy/nginx/plantai.conf`(SSE 长连接 + 大文件上传适配,随安装包发布到 `install/nginx/`) | ## 1. 编译阶段(构建机) @@ -121,12 +122,65 @@ docker load -i /tmp/plantai-bioflow-images.tar # 创建 bioflow_service 部署树 + .env(DOCGEN_LLM_*、BIOFLOW_IMAGE_MAP_PATH 指向 bioflow_kernel/assets 内的 stage_image_map.json)+ bash bioflow_service/restart.sh ``` +## 5b. nginx 安装与 80 端口代理(目标机,从零开始) + +> 目标机此前没有 nginx。本节让 80 端口成为唯一客户入口;8090 等全部服务只回环可达。 +> **切换顺序是硬约束**:先装 nginx 并经 80 验证反代正常,再执行 BFF 改绑,避免客户访问断档。 + +```bash +# 1. 安装(apt/yum 两系通用探测;需 root 或 sudo) +command -v apt-get >/dev/null && (apt-get update && apt-get install -y nginx) \ + || (yum install -y nginx) + +# 2. 放置配置模板(conf.d 目录因发行版而异:先看 nginx -t 输出里的 include 路径, +# 常见 /etc/nginx/conf.d/ 或 /etc/nginx/conf.d/*.conf) +cp /srv/plantai/install/nginx/plantai.conf /etc/nginx/conf.d/plantai.conf +# 如 server_name 需要固定域名/内网 IP:sed -i 's/server_name _;/server_name 192.168.x.x;/' /etc/nginx/conf.d/plantai.conf + +# 3. 语法校验 + 启用 +nginx -t +systemctl enable --now nginx 2>/dev/null || nginx # 无 systemd 的发行版直接 nginx 启动 + +# 4. 防火墙放行 80(如目标机有 ufw/firewalld) +ufw allow 80/tcp 2>/dev/null || true +firewall-cmd --add-service=http --permanent && firewall-cmd --reload 2>/dev/null || true + +# 5. 经 80 验证反代(此时 8090 仍是旧绑定也没关系——80 → 127.0.0.1:8090 已通) +curl -s http://127.0.0.1:80/ | grep -o '[^<]*' +curl -s http://127.0.0.1:80/api/health | python3 -m json.tool | head -5 + +# 6. BFF 改绑 127.0.0.1(start_all.sh 与 bff_restart.sh 默认已是 127.0.0.1): +# 用新版 start_all.sh 重启,或 bash deploy/bff_restart.sh(无参即 127.0.0.1) +ss -tln | grep ':8090 ' # 期望 127.0.0.1:8090,不再有 0.0.0.0 + +# 7. 内网最终验证 +curl -s http://<目标机内网IP>:80/ | grep -o '<title>[^<]*' +``` + +nginx 模板关键适配(勿删勿改,详见 `deploy/nginx/plantai.conf` 注释): +- **SSE**(/api/qa/chat/stream、/api/bioflow/*):`proxy_buffering off` + `proxy_read_timeout 3600s`(> BFF 看门狗 1200s),否则问答/生信流会被 nginx 缓冲或掐断。 +- **大文件上传**(上传无大小限制;生信基因组数百 MB):`client_max_body_size 0` + `proxy_request_buffering off` + `proxy_send_timeout 600s`。 +- 静态资源由 BFF 自身托管(ui/dist),nginx 只做反代,不自管静态目录。 + ## 6. 部署后完整质检(agent 逐条执行并记录结果,全过才算部署成功) ```bash # 6.1 进程与端口 ss -tln | grep -E ':(8090|8091|8092|8093|8094|8098)' # 8090=0.0.0.0,其余 127.0.0.1 +# 6.1b nginx 专项 +systemctl is-active nginx 2>/dev/null || pgrep -x nginx # nginx 存活 +ss -tln | grep ':80 ' # 80 端口监听(0.0.0.0 或目标机内网 IP) +curl -s --max-time 5 http://127.0.0.1:80/ | grep -o '<title>[^<]*' # 经 80 首页可达 +curl -s --max-time 10 -N -X POST http://127.0.0.1:80/api/qa/chat/stream \ + -H 'Content-Type: application/json' \ + -d '{"question":"水稻SPL基因家族的功能研究有哪些关键进展?","use_llm":true,"session_id":"nginx-smoke"}' \ + | head -c 300 # 期望收到 "event: progress" 或 "event: complete" 帧(SSE 未被缓冲) +printf 'nginx 上传冒烟' > /tmp/nginx-upload-smoke.txt +curl -s --max-time 120 -X POST http://127.0.0.1:80/api/docgen/library \ + -F 'file=@/tmp/nginx-upload-smoke.txt' -F 'name=nginx上传冒烟' -F 'as_template=false' | head -c 200 +# 期望返回 ok:true + items(经 80 上传可用);记录 library_id 便于清理(DELETE /api/docgen/library/{id}) + # 6.2 健康检查 curl -s http://127.0.0.1:8090/api/health | python3 -m json.tool # status ok、upstreams 全 ok curl -s http://127.0.0.1:8094/api/vstore/health # ok、count 与 chunk_count @@ -157,3 +211,4 @@ curl -s 'http://127.0.0.1:8094/api/vstore/search?q=测试&as_template=false' | p 3. **Neo4j normalized 数据(8.2G)按设计明文冷拷**(存储引擎限制,08-24 起无写入),属公开范围内例外,见 KB_ENCRYPT_GUIDE.md。 4. **构建机与目标机若为同一台机器**(内网 192.168.0.175 现状),部署就是替换现有 `plantai-rag-new-deploy-unified/` 部署树;执行前先备份、执行后按 §6 全量质检。 5. 本手册基于 2026-09-08 服务器实测编写;如工具链或目录结构有变,先对照仓库实际脚本修正本手册再执行。 +6. **当前生产服务器(192.168.0.175)仍是 0.0.0.0:8090 直连形态,尚未执行 §5b 的 nginx 迁移**——启动脚本默认值已改为 127.0.0.1,但现网进程仍是旧绑定;迁移时按 §5b 顺序执行(先 nginx 后改绑),不要直接无参重启 bff_restart.sh 以免客户访问断档。 diff --git a/sdk/run.sh b/sdk/run.sh index 74e881e..a2387a6 100755 --- a/sdk/run.sh +++ b/sdk/run.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# run.sh —— 本地起 BFF(ARCHITECTURE.md §3:0.0.0.0:8090,占用则退 8091)。 +# run.sh —— 本地起 BFF(ARCHITECTURE.md §3:127.0.0.1:8090,nginx 80 为唯一客户入口)。 # 用法:bash sdk/run.sh # 2026-09-01 统一 Python:conda plantai-bff → plantai-rag-new-venv(py3.12.13) set -euo pipefail @@ -9,4 +9,4 @@ PORT="${PORT:-8090}" PYTHON="${PLANTAI_BFF_PYTHON:-/home/xzq/5090/teamWorkspace/zh/plantai-rag-new-venv/bin/python}" [[ -x "$PYTHON" ]] || { echo "run.sh: 统一 venv 不可执行: $PYTHON" >&2; exit 1; } -exec "$PYTHON" -m uvicorn app.main:app --host 0.0.0.0 --port "$PORT" +exec "$PYTHON" -m uvicorn app.main:app --host 127.0.0.1 --port "$PORT" diff --git a/tooling/build_all.sh b/tooling/build_all.sh index dbb1c15..608858f 100755 --- a/tooling/build_all.sh +++ b/tooling/build_all.sh @@ -100,6 +100,9 @@ cp -r "$BUILD_ROOT/compiled/vstore/vstore" "$RELEASE_ROOT/vstore" rm -rf "$RELEASE_ROOT/vstore/tests" "$RELEASE_ROOT/vstore/__pycache__" cp "$PROJECT_ROOT/vstore/vstore_restart.sh" "$RELEASE_ROOT/vstore_restart.sh" cp "$PROJECT_ROOT/deploy/ollama_restart.sh" "$RELEASE_ROOT/ollama_restart.sh" +# nginx 80 端口反代模板(目标机从零安装章节引用,见 docs/DEPLOY_FLOW.md §5b) +mkdir -p "$RELEASE_ROOT/nginx" +cp "$PROJECT_ROOT/deploy/nginx/plantai.conf" "$RELEASE_ROOT/nginx/plantai.conf" # env 模板(VSTORE_ROOT/KEY/EMBED 等;真实值不入包) cp "$PROJECT_ROOT/vstore/.env.example" "$RELEASE_ROOT/vstore/.env.example" 2>/dev/null || true @@ -114,10 +117,10 @@ cp "$PROJECT_ROOT/sdk/.env.example" "$RELEASE_ROOT/sdk/.env.example" 2>/dev/null cat > "$RELEASE_ROOT/start_all.sh" <<'DEPLOY' #!/usr/bin/env bash # start_all.sh —— 安装目录一键启动(端口 8090 段) -# 用法:bash start_all.sh [bind] (bind 默认 0.0.0.0) +# 用法:bash start_all.sh [bind] (bind 默认 127.0.0.1——nginx 80 为唯一客户入口) set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -BIND="${1:-0.0.0.0}" +BIND="${1:-127.0.0.1}" echo "== 启动 PlantAI-rag-new 四服务 ==" # 向量化本地模型(bge-m3 嵌入):先拉起 Ollama(已运行则跳过),模型缺失只告警不阻断 bash "$ROOT/ollama_restart.sh" 2>/dev/null || echo "[ollama] 拉起失败,向量化降级(不阻断其余服务)"