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、云端归档根未建),未部署、未改云端任何状态。
67 lines
3.0 KiB
YAML
67 lines
3.0 KiB
YAML
# 云测试用作发布目标时的 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
|