Files
knowledge-governance/deploy/cloud-test/pg-forward.sh
T
姚章浩 468ae64918
build / build (push) Successful in 1m19s
fix(deploy): 修正云执行器套接字与凭据挂载契约
2026-10-30 20:37:18 +08:00

64 lines
3.7 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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/.s.PGSQL.5432),执行器容器把该目录
# 挂进去,DSN 用 host=/run/kgtest-pg。**推荐**:没有 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/.s.PGSQL.5432}"
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)
[[ "$REMOTE_SOCKET" =~ ^/[A-Za-z0-9_/-]+/\.s\.PGSQL\.5432$ ]] || die "REMOTE_SOCKET 必须是绝对目录下的 .s.PGSQL.5432"
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=$(dirname "$REMOTE_SOCKET")&port=5432&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