- start.sh×3: venv 解析改为安装包内 ../venv 优先(175 旧路径回退), 176 等目标机免改 - build_all.sh: start_all 模板补 vstore 拉起 + BFF 前 source sdk/.env + PYBIN 可移植解析 + env 目录 mkdir - DEPLOY_FLOW.md: §5.1 重写(176 实战模板: venv/torch 安装顺序/.env 键/ollama 离线携带/下载源可达性/内网直连), §0 增 176 已部署行 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
176 lines
9.0 KiB
Bash
Executable File
176 lines
9.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# build_all.sh —— 一键将 4 部分最新版本编译打包为安装目录 + 部署脚本。
|
||
# 流水线:编译 SDK+3 agent → 双审计 → 冒烟 → (定版后:KB 加密打包)→ 组装 → SHA256SUMS → 泄露门禁
|
||
# 用法:bash tooling/build_all.sh [版本] (版本默认读 tooling.env VERSION)
|
||
set -euo pipefail
|
||
umask 027
|
||
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||
. "$SCRIPT_DIR/tooling.env"
|
||
VERSION="${1:-$VERSION}"
|
||
BUILD_ROOT="$SCRIPT_DIR/build/$VERSION"
|
||
RELEASE_ROOT="$BUILD_ROOT/install"
|
||
|
||
echo "== build_all.sh $VERSION =="
|
||
echo "工程根: $PROJECT_ROOT"
|
||
mkdir -p "$BUILD_ROOT"
|
||
|
||
# ---- 1. 编译四部分 ----
|
||
echo "[1/6] 编译 SDK + 3 agent"
|
||
"$SDK_PYTHON" -c 'import Cython' || { echo "SDK_PYTHON 缺 Cython" >&2; exit 1; }
|
||
"$QA_PYTHON" -c 'import Cython' || { echo "QA_PYTHON 缺 Cython" >&2; exit 1; }
|
||
"$LEGACY_PYTHON" -c 'import Cython' || { echo "LEGACY_PYTHON 缺 Cython" >&2; exit 1; }
|
||
|
||
rm -rf "$BUILD_ROOT/compiled"
|
||
mkdir -p "$BUILD_ROOT/compiled"
|
||
bash "$SCRIPT_DIR/compile/compile_sdk.sh" \
|
||
"$PROJECT_ROOT/sdk" "$BUILD_ROOT/compiled/sdk" "$SDK_PYTHON"
|
||
bash "$SCRIPT_DIR/compile/compile_qa.sh" \
|
||
"$PROJECT_ROOT/agent/qa" "$BUILD_ROOT/compiled/qa" "$QA_PYTHON"
|
||
bash "$SCRIPT_DIR/compile/compile_methodology.sh" \
|
||
"$PROJECT_ROOT/agent/methodology" "$BUILD_ROOT/compiled/methodology" "$METHODOLOGY_PYTHON"
|
||
bash "$SCRIPT_DIR/compile/compile_legacy.sh" \
|
||
"$PROJECT_ROOT/agent/legacy-rag" "$BUILD_ROOT/compiled/legacy-rag" "$LEGACY_PYTHON"
|
||
|
||
# 向量库服务(本地嵌入 + 私有资料问答检索;api.py 白名单明文,其余编译 .so)
|
||
bash "$SCRIPT_DIR/compile/compile_vstore.sh" \
|
||
"$PROJECT_ROOT/vstore" "$BUILD_ROOT/compiled/vstore" "$SDK_PYTHON"
|
||
|
||
# ---- 2. 双审计(各树用编译时的 Python——ABI 后缀必须匹配) ----
|
||
echo "[2/6] 编译树审计"
|
||
AUDIT="$SCRIPT_DIR/compile/tools/audit_compiled_tree.py"
|
||
declare -A TREE_PY=( [sdk]="$SDK_PYTHON" [qa]="$QA_PYTHON" [methodology]="$METHODOLOGY_PYTHON" [legacy-rag]="$LEGACY_PYTHON" )
|
||
for tree in sdk qa methodology legacy-rag; do
|
||
py="${TREE_PY[$tree]}"
|
||
"$py" "$AUDIT" --tree "$BUILD_ROOT/compiled/$tree" --project "$tree" --write-marker \
|
||
| python3 -c "import json,sys; r=json.load(sys.stdin); print(f' $tree: ok={r[\"ok\"]} exts={r[\"extension_count\"]}'); sys.exit(0 if r['ok'] else 1)" \
|
||
|| { echo "$tree 审计失败" >&2; exit 2; }
|
||
"$py" "$AUDIT" --tree "$BUILD_ROOT/compiled/$tree" --project "$tree" --require-marker \
|
||
>/dev/null || { echo "$tree marker 校验失败" >&2; exit 2; }
|
||
done
|
||
|
||
# ---- 3. 冒烟(起服务探 /health,全 .so import 检查) ----
|
||
echo "[3/6] 冒烟(import 检查,服务起停由部署脚本承担)"
|
||
for tree in sdk qa methodology legacy-rag; do
|
||
py="$SDK_PYTHON"; [ "$tree" = "qa" ] && py="$QA_PYTHON"; [ "$tree" = "methodology" ] && py="$METHODOLOGY_PYTHON"; [ "$tree" = "legacy-rag" ] && py="$LEGACY_RUN_PYTHON"
|
||
if [ "$tree" = "sdk" ]; then
|
||
( cd "$BUILD_ROOT/compiled/sdk" && PYTHONPATH=. "$py" -c "import app.main" )
|
||
elif [ "$tree" = "qa" ]; then
|
||
( cd "$BUILD_ROOT/compiled/qa" && PYTHONPATH=.:./src "$py" -c "import scripts.qa_v1_1_73_server" )
|
||
elif [ "$tree" = "methodology" ]; then
|
||
( cd "$BUILD_ROOT/compiled/methodology" && PYTHONPATH=. "$py" -c "import scripts.methodology_server" )
|
||
else
|
||
( cd "$BUILD_ROOT/compiled/legacy-rag" && PYTHONPATH=. "$py" -c "import api.app" )
|
||
# vstore 冒烟(与四树同模式:全 .so import 检查)
|
||
( cd "$BUILD_ROOT/compiled/vstore" && PYTHONPATH=. "$SDK_PYTHON" -c "import vstore.api" )
|
||
fi
|
||
echo " $tree import OK"
|
||
done
|
||
|
||
# ---- 4. KB(定版后 SKIP_KB=0 启用) ----
|
||
if [ "${SKIP_KB:-1}" = "0" ]; then
|
||
echo "[4/6] KB 加密打包(定版后)"
|
||
KB_KEY_FILE="${KB_KEY_FILE:-$BUILD_ROOT/kb.key}"
|
||
[ -f "$KB_KEY_FILE" ] || { echo "缺 KB 密钥: $KB_KEY_FILE" >&2; exit 1; }
|
||
KB_KEY_FILE="$KB_KEY_FILE" bash "$SCRIPT_DIR/kb/encrypt_kb.sh" "$VERSION"
|
||
else
|
||
echo "[4/6] KB 跳过(SKIP_KB=1,数据库未定版;操作见 tooling/KB_ENCRYPT_GUIDE.md)"
|
||
fi
|
||
|
||
# ---- 5. 组装安装目录 ----
|
||
echo "[5/6] 组装安装目录"
|
||
rm -rf "$RELEASE_ROOT"
|
||
mkdir -p "$RELEASE_ROOT"
|
||
cp -r "$BUILD_ROOT/compiled/sdk" "$RELEASE_ROOT/sdk"
|
||
cp -r "$BUILD_ROOT/compiled/qa" "$RELEASE_ROOT/qa"
|
||
cp -r "$BUILD_ROOT/compiled/methodology" "$RELEASE_ROOT/methodology"
|
||
cp -r "$BUILD_ROOT/compiled/legacy-rag" "$RELEASE_ROOT/legacy-rag"
|
||
# UI 产物
|
||
( cd "$PROJECT_ROOT/ui" && npm run build --silent ) || { echo "ui build 失败" >&2; exit 5; }
|
||
mkdir -p "$RELEASE_ROOT/ui"
|
||
cp -r "$PROJECT_ROOT/ui/dist" "$RELEASE_ROOT/ui/dist"
|
||
# 启动脚本模板
|
||
cp "$PROJECT_ROOT/agent/qa/scripts/"*.sh "$RELEASE_ROOT/qa/scripts/" 2>/dev/null || true
|
||
cp "$PROJECT_ROOT/agent/methodology/scripts/"*.sh "$RELEASE_ROOT/methodology/scripts/" 2>/dev/null || true
|
||
cp "$PROJECT_ROOT/agent/legacy-rag/scripts/"*.sh "$RELEASE_ROOT/legacy-rag/scripts/" 2>/dev/null || true
|
||
|
||
# 向量化环节(本地模型):vstore 明文源码 + 启动脚本 + Ollama 拉起脚本
|
||
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"
|
||
# QA 数据库裸进程部署脚本(systemd 标准,见 docs/DEPLOY_FLOW.md §5「QA 数据库」)
|
||
mkdir -p "$RELEASE_ROOT/qa-db"
|
||
cp -r "$PROJECT_ROOT/deploy/qa-db/"*.sh "$RELEASE_ROOT/qa-db/" 2>/dev/null || true
|
||
cp -r "$PROJECT_ROOT/deploy/qa-db/"*.service "$RELEASE_ROOT/qa-db/" 2>/dev/null || true
|
||
# 离线二进制载体(deploy/qa-db/bin/ 为 gitignore;存在则随包分发,目标机免下载)
|
||
[ -d "$PROJECT_ROOT/deploy/qa-db/bin" ] && cp -r "$PROJECT_ROOT/deploy/qa-db/bin" "$RELEASE_ROOT/qa-db/bin" || true
|
||
# QA reranker 模型入包(构建机仓库同级 PlantAI-rag;缺失只告警不阻断)
|
||
RERANKER_SRC="$PROJECT_ROOT/../PlantAI-rag/bge-reranker-base"
|
||
if [ -d "$RERANKER_SRC" ]; then
|
||
mkdir -p "$RELEASE_ROOT/models"
|
||
cp -r "$RERANKER_SRC" "$RELEASE_ROOT/models/bge-reranker-base"
|
||
echo "reranker 模型已入包: models/bge-reranker-base"
|
||
else
|
||
echo "警告: reranker 模型源不存在($RERANKER_SRC),安装包不含本地 reranker"
|
||
fi
|
||
# env 模板(VSTORE_ROOT/KEY/EMBED 等;真实值不入包)
|
||
cp "$PROJECT_ROOT/vstore/.env.example" "$RELEASE_ROOT/vstore/.env.example" 2>/dev/null || true
|
||
|
||
# env 模板
|
||
for t in qa methodology legacy-rag; do
|
||
mkdir -p "$RELEASE_ROOT/$t/env"
|
||
cp "$PROJECT_ROOT/agent/$t/env/prod.env.example" "$RELEASE_ROOT/$t/env/prod.env.example" 2>/dev/null || true
|
||
done
|
||
cp "$PROJECT_ROOT/sdk/.env.example" "$RELEASE_ROOT/sdk/.env.example" 2>/dev/null || true
|
||
# KB 包(定版后)
|
||
[ -f "$BUILD_ROOT/knowledge-$VERSION.tar" ] && cp "$BUILD_ROOT/knowledge-$VERSION.tar"* "$RELEASE_ROOT/"
|
||
# 部署脚本
|
||
cat > "$RELEASE_ROOT/start_all.sh" <<'DEPLOY'
|
||
#!/usr/bin/env bash
|
||
# start_all.sh —— 安装目录一键启动(端口 8090 段)
|
||
# 用法:bash start_all.sh [bind] (bind 默认 127.0.0.1——nginx 80 为唯一客户入口)
|
||
set -euo pipefail
|
||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
BIND="${1:-127.0.0.1}"
|
||
# Python 解析:安装包内 venv 优先(install/venv,可链到部署根),缺失退回 PATH python3
|
||
PYBIN="${PLANTAI_PYTHON:-$ROOT/venv/bin/python}"
|
||
[[ -x "$PYBIN" ]] || PYBIN="$(command -v python3)"
|
||
echo "== 启动 PlantAI-rag-new 四服务 =="
|
||
# 向量化本地模型(bge-m3 嵌入):先拉起 Ollama(已运行则跳过),模型缺失只告警不阻断
|
||
bash "$ROOT/ollama_restart.sh" 2>/dev/null || echo "[ollama] 拉起失败,向量化降级(不阻断其余服务)"
|
||
bash "$ROOT/qa/scripts/start.sh" 8091 || true
|
||
bash "$ROOT/methodology/scripts/start.sh" 8092 || true
|
||
bash "$ROOT/legacy-rag/scripts/start.sh" 8093 app || true
|
||
bash "$ROOT/vstore_restart.sh" || echo "[vstore] 拉起失败,向量化不可用(不阻断其余服务)"
|
||
sleep 3
|
||
# BFF env:sdk/.env 含 DOCGEN_LLM_*、VSTORE_BASE_URL、BFF_NEO4J_*(无此 env BFF 上游不可用)
|
||
set -a
|
||
[ -f "$ROOT/sdk/.env" ] && . "$ROOT/sdk/.env"
|
||
set +a
|
||
( cd "$ROOT/sdk" && setsid "$PYBIN" -m uvicorn app.main:app --host "$BIND" --port 8090 \
|
||
> /tmp/plantai-sdk.log 2>&1 < /dev/null & )
|
||
echo "BFF 启动中(8090),5 秒后自检:"
|
||
sleep 5
|
||
curl -s --max-time 15 http://127.0.0.1:8090/api/health | head -c 300
|
||
echo
|
||
DEPLOY
|
||
chmod +x "$RELEASE_ROOT/start_all.sh"
|
||
|
||
# ---- 6. SHA256SUMS + 泄露门禁 ----
|
||
echo "[6/6] SHA256SUMS + 泄露检查"
|
||
( cd "$RELEASE_ROOT" && find . -type f -exec sha256sum {} \; | sort -k2 > SHA256SUMS )
|
||
LEAKS=$(grep -rnE "BEGIN (RSA |EC |OPENSSH )?PRIVATE KEY|sk-[a-zA-Z0-9]{20}|kb\.key" "$RELEASE_ROOT" 2>/dev/null | grep -v SHA256SUMS | head -5 || true)
|
||
if [ -n "$LEAKS" ]; then
|
||
echo "泄露门禁失败:" >&2; echo "$LEAKS" >&2; exit 6
|
||
fi
|
||
echo "泄露检查: 净"
|
||
echo
|
||
echo "== 构建完成: $RELEASE_ROOT =="
|
||
du -sh "$RELEASE_ROOT"
|
||
echo "下一步:空目录全新安装验收(备用端口 8094/8095/8096/8097)"
|