e6472b0ec6
为什么改:发布执行链是"与目标同机"假设写死的(本机 docker.sock、本机 drain.json、 本机 Redis/PG),把目标换成云测试不能只改展示 URL;直接搬整套 worker 又会抢走 本机封存/QA/周报队列并按本机配置写错目标。所以先把"谁消费哪段队列"变成显式角色, 再补齐跨主机搬运与目标侧门禁。 角色(LIBRARY_WORKER_ROLE=full/release-executor/capture)不只影响 handler 列表, 还决定是否拥有 DDL(release-executor 只读校验迁移版本,落后即拒绝启动)、 收拾哪些 library_jobs.kind、是否跑 release 接管扫描、是否起 scheduler/QA/周报/探测。 capture 保留本机原有全部业务;release-executor 只挂 sync/restore/recover/baseline。 快照跨主机:新增内容寻址的 bundle(版本清单先落、blob 按 sha256 命名、清单最后 Link 作提交点),pack/unpack 幂等且拒绝覆盖与同名不同内容;执行器使用前仍逐 blob 重算 sha256,因此传输不可变有两道证据。 目标侧门禁:目标知识库 graph_enabled=true 时拒绝发布(发布只写 PG/ES/OSS,不写 Neo4j;未知也拒绝),只读检测、不改目标配置、不做图谱迁移。 云端入口:新增 drain 感知的 ingress 闸门(建连超时与读超时分离,半关闭单向传播, SIGTERM 排空后写 drain.json 并 exit 0/2)、compose 叠加片段(app 不再发布端口、 frontend 与 adapter 的入口收敛到闸门、指向真实网络 weknora-test-v071-network)、 执行器启动脚本与治理 PG 反向隧道脚本(默认 unix socket,不占 TCP)。 验证:deploy/cloud-test/test_gate.py 13 项全 PASS(含 12 秒静默流、半关闭、2MiB 完整、 排空 exit 0/active_at_close=1、排空超时 exit 2、上游不可达不挂住);go test 相关包全绿; scripts/ci_checks.py 16 项全部 success(EXIT=0,1241 用例通过/0 失败/191 已声明可选集成跳过); 云测试只读预检 17 项 / 6 FAIL,FAIL 项即当前部署缺口(无闸门、app 仍发布端口、 adapter 与 frontend 仍直连 app、云端归档根未建),未部署、未改云端任何状态。
63 lines
3.5 KiB
Bash
Executable File
63 lines
3.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# 治理库 → 云测试发布执行器:SSH 加密反向转发(在**本机控制面**上运行)。
|
||
#
|
||
# 为什么不能写 localhost:5432:本机治理 PG 跑在 Docker 里,没有 5432 宿主机发布,
|
||
# 也不允许为它开公网/主机端口。所以只能:
|
||
# 1. 先解析 PG 容器在它自己网络里的真实 IP;
|
||
# 2. 用 ssh -R 建反向转发,让云侧出现一个**只属于云主机/容器**的入口;
|
||
# 3. 执行器通过这个入口连库,凭据只在本机与云端 0600 env 之间传递。
|
||
#
|
||
# 两种模式(默认 streamlocal,不占 TCP 端口、不开监听):
|
||
# streamlocal 云侧生成 unix socket(如 /run/kgtest-pg/pg.sock),执行器容器把该目录
|
||
# 挂进去,DSN 用 host=/run/kgtest-pg/pg.sock。**推荐**:没有 TCP 暴露,
|
||
# 不受"容器看不到宿主机 127.0.0.1"影响。
|
||
# tcp 云侧 127.0.0.1:15433 loopback。⚠️ 只有云**宿主机**上的进程能用;
|
||
# 容器里的进程看到的 127.0.0.1 是容器自己。要用必须在云侧再加一个
|
||
# 从 docker bridge 到 127.0.0.1 的桥接(socat/haproxy),那属于父运维决定,
|
||
# 本脚本不替你开。
|
||
#
|
||
# 用法:
|
||
# MODE=streamlocal bash deploy/cloud-test/pg-forward.sh
|
||
# MODE=tcp REMOTE_PORT=15433 bash deploy/cloud-test/pg-forward.sh
|
||
set -euo pipefail
|
||
|
||
SSH_HOST="${SSH_HOST:-weknora-test}"
|
||
PG_CONTAINER="${PG_CONTAINER:-knowledge-governance-p1-postgres-1}"
|
||
MODE="${MODE:-streamlocal}"
|
||
REMOTE_SOCKET="${REMOTE_SOCKET:-/run/kgtest-pg/pg.sock}"
|
||
REMOTE_PORT="${REMOTE_PORT:-15433}"
|
||
|
||
die() { echo "pg-forward: $*" >&2; exit 1; }
|
||
|
||
command -v docker >/dev/null || die "需要 docker(解析治理 PG 容器 IP)"
|
||
docker inspect "$PG_CONTAINER" >/dev/null 2>&1 || die "找不到容器 $PG_CONTAINER"
|
||
|
||
# 只取第一个网络里的 IP;多网络时打印提示,由人确认走哪个。
|
||
IPS=$(docker inspect -f '{{range $name, $net := .NetworkSettings.Networks}}{{$name}}={{$net.IPAddress}} {{end}}' "$PG_CONTAINER")
|
||
PG_IP=$(echo "$IPS" | tr ' ' '\n' | sed -n 's/^[^=]*=\([0-9.]\+\)$/\1/p' | head -n1)
|
||
[ -n "$PG_IP" ] || die "解析不到 $PG_CONTAINER 的容器 IP(网络:$IPS)"
|
||
echo "pg-forward: 治理 PG 容器 $PG_CONTAINER -> $PG_IP:5432(网络:$IPS)"
|
||
|
||
case "$MODE" in
|
||
streamlocal)
|
||
ssh -o BatchMode=yes -o ExitOnForwardFailure=yes -o ServerAliveInterval=15 -o ServerAliveCountMax=3 \
|
||
"$SSH_HOST" "install -d -m 0700 -o root -g root $(dirname "$REMOTE_SOCKET")"
|
||
DSN_SHAPE="postgres://<user>@/<db>?host=$REMOTE_SOCKET&sslmode=disable"
|
||
echo "pg-forward: 云侧入口 unix socket = $REMOTE_SOCKET(仅云主机与挂载它的容器可见)"
|
||
echo "pg-forward: 执行器容器必须挂载 -v $(dirname "$REMOTE_SOCKET"):$(dirname "$REMOTE_SOCKET")"
|
||
echo "pg-forward: DATABASE_URL 形状 = $DSN_SHAPE"
|
||
exec ssh -N -o BatchMode=yes -o ExitOnForwardFailure=yes \
|
||
-o ServerAliveInterval=15 -o ServerAliveCountMax=3 \
|
||
-R "$REMOTE_SOCKET:$PG_IP:5432" "$SSH_HOST"
|
||
;;
|
||
tcp)
|
||
echo "pg-forward: 云侧 127.0.0.1:$REMOTE_PORT -> 本机 $PG_IP:5432(仅云宿主机可用)"
|
||
echo "pg-forward: 容器内进程不能用这个 loopback;要么用 MODE=streamlocal,要么另做 bridge(父决定)"
|
||
exec ssh -N -o BatchMode=yes -o ExitOnForwardFailure=yes \
|
||
-o ServerAliveInterval=15 -o ServerAliveCountMax=3 \
|
||
-R "127.0.0.1:$REMOTE_PORT:$PG_IP:5432" "$SSH_HOST"
|
||
;;
|
||
*)
|
||
die "MODE 只能是 streamlocal 或 tcp(当前 $MODE)"
|
||
;;
|
||
esac |