Files
knowledge-governance/deploy/cloud-test/compose.release-overlay.yaml
姚章浩 e6472b0ec6 feat(library): 云测试发布目标接入的角色分离、快照搬运与图谱门禁
为什么改:发布执行链是"与目标同机"假设写死的(本机 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、云端归档根未建),未部署、未改云端任何状态。
2026-10-30 18:38:38 +08:00

67 lines
3.0 KiB
YAML
Raw Permalink 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.
# 云测试用作发布目标时的 compose 叠加片段(project: weknora-test-v071)
#
# 作用:把"唯一入口"这个不变量在云测试上真正建立起来,让维护窗口有可信的排空证据。
# 1. app 不再发布宿主机端口(写入者发布端口 = 存在绕开闸门的直连通道,拓扑校验会拒绝);
# 2. 新增 ingress 闸门,成为宿主机 8080 上唯一的 HTTP 入口,并在 SIGTERM 时写 drain.json;
# 3. frontend 的 API 目标改为 ingress(这样网页流量也走闸门,关闸门 = 站点真的关)。
#
# 使用(父执行,先校验再应用):
# docker compose -f compose.yaml -f compose.release-overlay.yaml config >/dev/null
# docker compose -f compose.yaml -f compose.release-overlay.yaml up -d app ingress frontend
#
# !reset 需要 Docker Compose >= 2.24(云端实测 2.40.3)。
#
# 网络:本项目实际网络名是 weknora-test-v071-network(不是 compose 默认的 *_default)。
# 网络:本项目实际网络名是 weknora-test-v071-network(不是 compose 默认的 *_default)。
# ingress 用独立 key `release_target` 以 external 方式加入它:既不重定义原 default,
# 也不靠"默认网络恰好同名"这种巧合。
name: weknora-test-v071
services:
app:
# 写入者不发布端口;验证器/发布执行器的直连走 docker 网络里的服务名 app:8080。
ports: !reset []
ingress:
# 唯一对外入口:关入口=停这个闸门。镜像只用现成的 python,不构建、不改 WeKnora 镜像。
image: python:3.13-slim
container_name: kgtest-ingress
# restart: "no" 是硬约束:维护窗口把入口停下之后,Docker 不允许自己把它拉回来。
restart: "no"
command: ["python3", "/gate/gate.py"]
environment:
# 闸门监听端口 = 宿主机发布端口,入口 URL 用同端口,拓扑校验才可比对。
GATE_PORT: "8080"
GATE_UPSTREAM_HOST: app
GATE_UPSTREAM_PORT: "8080"
GATE_DRAIN_FILE: /gate-state/drain.json
GATE_DRAIN_TIMEOUT: "45"
ports:
- "127.0.0.1:8080:8080"
volumes:
# gate.py 与 state 都在宿主机固定目录;发布执行器挂同一个 state 目录,
# 所以"删除 drain 记录 / 读回排空证据"发生在同一个真实文件上。
- /srv/kgtest-gate/gate.py:/gate/gate.py:ro
- /srv/kgtest-gate/state:/gate-state
healthcheck:
test: ["CMD", "python3", "-c", "import socket;s=socket.create_connection(('127.0.0.1',8080),2);s.close()"]
interval: 3s
timeout: 3s
retries: 30
start_period: 5s
stop_grace_period: 60s
# 用独立 key 指向项目真实网络(external,不改原 compose 的 default 定义):
# 这样 ingress 与 app 在同一条网络里能按服务名互通,也不会凭空创建 *_default。
networks:
- release_target
frontend:
environment:
# 网页的 /api 也要经过闸门,否则"关入口"只关了一半。
APP_HOST: ingress
networks:
release_target:
external: true
name: weknora-test-v071-network