From c3f7d1f2223c29454b9cdeffe587842356c0ce7c Mon Sep 17 00:00:00 2001 From: kdletters Date: Wed, 17 Jun 2026 21:25:36 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=20Pingora=20=E7=9B=B4?= =?UTF-8?q?=E8=BF=9E=E9=AA=8C=E6=94=B6=E5=8F=A3=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 允许 direct live 接受 SpacetimeDB identity 的 405 真实响应 同步 Nginx README 与 Pingora 试点文档的直连验收说明 在 dev 服务器用真实 API、SpacetimeDB 和静态目录完成 shadow 验收 --- deploy/nginx/README.md | 2 +- docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md | 2 +- scripts/check-pingora-direct-live.mjs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/deploy/nginx/README.md b/deploy/nginx/README.md index 767615d63..d33842cf5 100644 --- a/deploy/nginx/README.md +++ b/deploy/nginx/README.md @@ -49,7 +49,7 @@ - API release 必须把 `scripts/check-pingora-release-readiness.mjs`、`scripts/check-pingora-canary-live.mjs`、`scripts/check-pingora-canary-access-log-parity.mjs`、`scripts/ops/pingora-current-release-audit.mjs`、`scripts/ops/pingora-cutover-status-snapshot.mjs`、`scripts/ops/pingora-cutover-evidence-bundle.mjs`、`scripts/check-pingora-direct-preflight.mjs`、`scripts/check-pingora-direct-live.mjs`、`scripts/check-production-health-patrol-env.mjs`、`scripts/deploy/pingora-health-patrol-env-switch.mjs`、`deploy/systemd/`、`deploy/env/` 和 `deploy/pingora/` 一起复制到 `/opt/genarrative/current`;current release 自审、直连启用、health patrol env 切换、canary live、access log 对账、cutover 状态快照和证据包脚本都从 current release 推导依赖路径,切换窗口不得依赖 Jenkins 工作区或目标机源码 checkout。 - 默认 systemd service 以 `genarrative` 非 root 用户运行,不具备绑定 `80/443` 的能力。Server-Provision 只安装 `/etc/genarrative/pingora/genarrative-pingora-gateway-direct-entry.conf` 作为人工启用模板;切直连低端口时必须先确认 `genarrative` 可读证书文件、Nginx 已释放 `80/443`,再执行 `/opt/genarrative/current/scripts/deploy/pingora-direct-enable.sh --apply --preflight-env-file /etc/genarrative/pingora-gateway.env --preflight-check-cert-readable --preflight-check-service-env-file --preflight-check-service-user-cert-readable --preflight-check-service-binary-executable --preflight-check-ports-free --direct-https-base-url https://127.0.0.1 --direct-http-base-url http://127.0.0.1 --direct-host <域名> --direct-redirect-host <域名或host:port> --direct-spacetime-database <库名> --direct-pingora-access-log /var/log/genarrative/pingora-gateway.access.log`;脚本会先执行随包 current release 自审,确认 `pingora-gateway` 可执行且 systemd `ExecStart` 指向 current release,失败时不会安装 drop-in。自审通过后才安装 drop-in、`systemctl daemon-reload` 并重启 Pingora;脚本会用 `systemctl cat` 确认 `CAP_NET_BIND_SERVICE` drop-in 已进入 systemd 最终配置,用 `systemctl show ... ExecStart` 确认最终 service 指向随包主 service 模板中的 current release `pingora-gateway`,用 `systemctl is-active` 确认 Pingora active,并执行 direct live smoke,强制覆盖 HTTPS / HTTP redirect / ACME / WSS 101 和 Pingora access log request_id 落盘。 - `npm run check:pingora-gateway-smoke` 会用临时自签证书覆盖 TLS 直连、HTTP redirect 和 WSS subscribe 行为;正式公网切换前仍必须先走 Nginx canary 和 release readiness 门禁。 -- 目标机直连入口启用后先运行 `npm run check:pingora-direct-preflight -- --env-file /etc/genarrative/pingora-gateway.env --require-live-env --systemd-cat --check-cert-readable --check-service-env-file --check-service-user-cert-readable --check-service-binary-executable --check-ports-free`,再运行 `npm run check:pingora-direct-live`,检查 HTTPS 根路径、HTTP/2 ALPN、代表性 API、SpacetimeDB identity、WSS subscribe 握手、generated 拒绝、公开 `/healthz` 拒绝、可选 shadow probe,以及 HTTP 301 / ACME challenge;release readiness 可用 `--require-direct --direct-https-base-url https://127.0.0.1 --direct-http-base-url http://127.0.0.1 --direct-host <域名> --direct-redirect-host <域名或host:port> --direct-spacetime-database <库名> --direct-pingora-access-log /var/log/genarrative/pingora-gateway.access.log --direct-health-patrol-env-file /etc/genarrative/health-patrol.env --direct-preflight-env-file /etc/genarrative/pingora-gateway.env --direct-preflight-systemd --direct-preflight-check-cert-readable --direct-preflight-check-service-env-file --direct-preflight-check-service-user-cert-readable --direct-preflight-check-service-binary-executable --direct-preflight-check-ports-free` 强制纳入同一条门禁,漏掉 direct HTTP base URL、正式域名 Host/SNI、redirect Location host、目标 SpacetimeDB 库、Pingora access log request_id 落盘、health patrol env direct 模式复核、systemd drop-in 生效检查、service EnvironmentFile 一致性检查、当前用户 / systemd 服务用户证书可读检查、service 二进制可执行检查或 80/443 端口释放检查都会直接失败。 +- 目标机直连入口启用后先运行 `npm run check:pingora-direct-preflight -- --env-file /etc/genarrative/pingora-gateway.env --require-live-env --systemd-cat --check-cert-readable --check-service-env-file --check-service-user-cert-readable --check-service-binary-executable --check-ports-free`,再运行 `npm run check:pingora-direct-live`,检查 HTTPS 根路径、HTTP/2 ALPN、代表性 API、SpacetimeDB identity、WSS subscribe 握手、generated 拒绝、公开 `/healthz` 拒绝、可选 shadow probe,以及 HTTP 301 / ACME challenge;真实 SpacetimeDB 对 `GET /v1/identity` 返回 `405 Method Not Allowed` 属于可接受语义,direct live 只把它作为路径转发代表,不要求该 GET 创建 identity;release readiness 可用 `--require-direct --direct-https-base-url https://127.0.0.1 --direct-http-base-url http://127.0.0.1 --direct-host <域名> --direct-redirect-host <域名或host:port> --direct-spacetime-database <库名> --direct-pingora-access-log /var/log/genarrative/pingora-gateway.access.log --direct-health-patrol-env-file /etc/genarrative/health-patrol.env --direct-preflight-env-file /etc/genarrative/pingora-gateway.env --direct-preflight-systemd --direct-preflight-check-cert-readable --direct-preflight-check-service-env-file --direct-preflight-check-service-user-cert-readable --direct-preflight-check-service-binary-executable --direct-preflight-check-ports-free` 强制纳入同一条门禁,漏掉 direct HTTP base URL、正式域名 Host/SNI、redirect Location host、目标 SpacetimeDB 库、Pingora access log request_id 落盘、health patrol env direct 模式复核、systemd drop-in 生效检查、service EnvironmentFile 一致性检查、当前用户 / systemd 服务用户证书可读检查、service 二进制可执行检查或 80/443 端口释放检查都会直接失败。 - direct live 在 HTTPS 根路径返回 `200` 且 HTML 中发现 `/assets/` 或 `/admin/assets/` 引用时,会自动请求该静态资源,确认 `Cache-Control`、`ETag`、`Last-Modified`、`Accept-Ranges: bytes`、`HEAD` 头响应、`If-None-Match` / `If-Modified-Since` 的 `304` 响应和 `Range: bytes=0-0` 的 `206 + Content-Range` 响应,并纳入 Pingora access log method/path/status 对账;若首页引用 Vite 指纹资源,还会额外确认 `Cache-Control: public, max-age=31536000, immutable` 以及指纹资源 GET / HEAD / 304 / Range access log 证据。维护模式、非 HTML 或发布包首页没有资产引用时该项标记为 skipped,不阻断维护窗口。 - 直连启用前先 dry-run `/opt/genarrative/current/scripts/deploy/pingora-direct-enable.sh --no-status`;验证失败时执行 `/opt/genarrative/current/scripts/deploy/pingora-direct-rollback.sh --apply --reload-nginx --nginx-smoke-url http://127.0.0.1/healthz --nginx-smoke-host <域名> --nginx-smoke-expect-body '"ok":true'`,脚本会先运行 `nginx -t`,通过后移除 direct-entry drop-in、重启 Pingora,用 `systemctl cat` 确认 `CAP_NET_BIND_SERVICE` 已从 systemd 最终配置中移除,用 `systemctl show ... ExecStart` 确认最终 service 仍指向随包主 service 模板中的 current release `pingora-gateway`,并 reload Nginx、确认 Nginx service 仍为 `active`,最后用 smoke URL 证明 Nginx 入口真实可访问;传入 `--nginx-smoke-expect-body` 时还会要求响应体包含该片段。仓库工作区可用 `npm run deploy:pingora-direct-enable -- --apply --preflight-env-file /etc/genarrative/pingora-gateway.env --preflight-check-cert-readable --preflight-check-service-env-file --preflight-check-service-user-cert-readable --preflight-check-service-binary-executable --preflight-check-ports-free --direct-https-base-url https://127.0.0.1 --direct-http-base-url http://127.0.0.1 --direct-host <域名> --direct-redirect-host <域名或host:port> --direct-spacetime-database <库名> --direct-pingora-access-log /var/log/genarrative/pingora-gateway.access.log` 和 `npm run deploy:pingora-direct-rollback -- --apply --reload-nginx --nginx-smoke-url http://127.0.0.1/healthz --nginx-smoke-host <域名> --nginx-smoke-expect-body '"ok":true'`。两个脚本默认 dry-run;启用脚本 `--apply` 必须先通过 current release 自审,并带 env、证书可读、service EnvironmentFile 一致性、服务用户证书可读、service 二进制可执行、端口释放预检、direct live 参数和 Pingora access log 参数,回退脚本 `--apply` 必须带 `--reload-nginx` 和 `--nginx-smoke-url`;如果 health patrol env 已预先切回 Nginx,也可追加 `--health-patrol-env-file /etc/genarrative/health-patrol.env --health-patrol-expected-public-base-url <切换前Nginx巡检入口> --health-patrol-require-empty-public-host` 让回退脚本在 Nginx smoke 后复核 `gateway mode=nginx` 且 public base URL / Host 已恢复,若切换前 Nginx 巡检本来需要 Host 覆盖,则把最后一项换成 `--health-patrol-expected-public-host <切换前Host>`;如果还要同时证明 shadow 高端口仍健康,可追加 `--pingora-shadow-probe-url http://127.0.0.1:18081/__genarrative_pingora/healthz --pingora-shadow-probe-token `,脚本会隐藏 token 并要求响应包含 `gateway=pingora-shadow`。本机 `npm run check:pingora-direct-enable` / `npm run check:pingora-direct-rollback` 会验证 dry-run 不会安装或删除临时 drop-in、current release 自审失败时启用脚本不会安装 drop-in,并展示启用 / 回退后的 systemd 最终配置核验、ExecStart 指向核验、Pingora active 核验、direct live smoke、Nginx 语法检查、reload 状态核验、Nginx smoke 及响应体片段核验、可选 health patrol env 复核和可选 shadow probe 复核。 - `npm run check:pingora-current-release-audit` 会烟测 current release 自审脚本;正式直连 runbook 会先执行 `/opt/genarrative/current/scripts/ops/pingora-current-release-audit.mjs --release-root /opt/genarrative/current --require-pingora-gateway --systemd-show`,只读确认发布包自包含、`api-server.sha256` / `pingora-gateway.sha256` 匹配、`release-manifest.api-server.json` 已登记 `pingora-gateway`、`pingora-gateway` 可执行且 systemd `ExecStart` 指向 current release。 diff --git a/docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md b/docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md index 8cafabdec..46375cb9d 100644 --- a/docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md +++ b/docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md @@ -213,7 +213,7 @@ GENARRATIVE_PINGORA_DIRECT_REDIRECT_HOST=<域名或host:port> \ npm run check:pingora-direct-live ``` -该脚本只读检查 HTTPS 根路径、HTTP/2 ALPN、代表性 API、SpacetimeDB identity、WSS `/v1/database//subscribe` 握手、generated 禁止入口、公开 `/healthz` 拒绝、可选 shadow probe,以及 HTTP 入口到 HTTPS 的 301 和 ACME challenge 静态读取;配置 `--pingora-access-log` 后还会为每个请求生成 `X-Request-Id` 并反查 Pingora access log,逐条比对同一 `request_id` 的 method、path 与 status,证明直连流量真实进入 Pingora,且未发生日志侧方法 / 路径 / 状态漂移。HTTP 响应必须带 `X-Genarrative-Gateway: pingora-shadow`,TLS ALPN 必须协商到 `h2`,WSS 成功握手时必须保留 `v2.bsatn.spacetimedb` 子协议。release readiness `--require-direct` 会自动要求 WSS 返回 101,并要求提供 direct HTTP base URL、正式域名 Host/SNI、redirect Location host、显式 SpacetimeDB 数据库名和 Pingora access log 路径,让 HTTP/2、HTTP redirect / ACME 入口、正式证书域名、跳转目标域名、目标库 subscribe 和 request_id + method/path/status 对账证据都纳入硬门禁;单独运行 direct live smoke 时也可加 `--require-wss-upgrade` 强制同一口径。direct live 在首页发现 `/assets/` 或 `/admin/assets/` 引用时会额外执行静态资源 GET、HEAD、`If-None-Match` / `If-Modified-Since` 条件请求和 `Range: bytes=0-0` 探针,确认静态头、HEAD 头响应、`304` 协商缓存、`206 + Content-Range` 以及不压缩 Range / 304 响应均进入同一 access log 证据链;这些静态 GET / HEAD / 304 / Range 的 JSON 结果会写入白名单 `headers`,只保留 `cache-control`、`etag`、`last-modified`、`accept-ranges`、`content-range`、`content-length` 和 `content-encoding`,方便切换后复盘缓存和 Range 响应头。若发现 Vite 指纹资源,还会额外确认 `Cache-Control: public, max-age=31536000, immutable` 及其 GET / HEAD / 304 / Range method/path/status 证据,避免旧 tab chunk 缓存口径在直连后退化。direct live 的 HTTPS / HTTP base URL、Host、redirect Host、probe token、额外 path、SpacetimeDB 数据库名、access log 路径、timeout 和布尔 env 都不能包含换行或 NUL;脚本会在发起 HTTPS / HTTP / WSS 请求前失败,避免污染参数进入请求头、URL、日志对账或 JSON 证据。环境变量示例见 `deploy/env/pingora-direct-live.env.example`。生产证书必须可被系统信任;`--insecure-tls` 只允许本机自签证书 smoke 使用。`--skip-wss` 只允许单独 direct live 临时排障,release readiness `--require-direct` 会直接拒绝。 +该脚本只读检查 HTTPS 根路径、HTTP/2 ALPN、代表性 API、SpacetimeDB identity、WSS `/v1/database//subscribe` 握手、generated 禁止入口、公开 `/healthz` 拒绝、可选 shadow probe,以及 HTTP 入口到 HTTPS 的 301 和 ACME challenge 静态读取;真实 SpacetimeDB 对 `GET /v1/identity` 返回 `405 Method Not Allowed` 属于可接受语义,direct live 只把它作为路径转发代表,不要求该 GET 创建 identity;配置 `--pingora-access-log` 后还会为每个请求生成 `X-Request-Id` 并反查 Pingora access log,逐条比对同一 `request_id` 的 method、path 与 status,证明直连流量真实进入 Pingora,且未发生日志侧方法 / 路径 / 状态漂移。HTTP 响应必须带 `X-Genarrative-Gateway: pingora-shadow`,TLS ALPN 必须协商到 `h2`,WSS 成功握手时必须保留 `v2.bsatn.spacetimedb` 子协议。release readiness `--require-direct` 会自动要求 WSS 返回 101,并要求提供 direct HTTP base URL、正式域名 Host/SNI、redirect Location host、显式 SpacetimeDB 数据库名和 Pingora access log 路径,让 HTTP/2、HTTP redirect / ACME 入口、正式证书域名、跳转目标域名、目标库 subscribe 和 request_id + method/path/status 对账证据都纳入硬门禁;单独运行 direct live smoke 时也可加 `--require-wss-upgrade` 强制同一口径。direct live 在首页发现 `/assets/` 或 `/admin/assets/` 引用时会额外执行静态资源 GET、HEAD、`If-None-Match` / `If-Modified-Since` 条件请求和 `Range: bytes=0-0` 探针,确认静态头、HEAD 头响应、`304` 协商缓存、`206 + Content-Range` 以及不压缩 Range / 304 响应均进入同一 access log 证据链;这些静态 GET / HEAD / 304 / Range 的 JSON 结果会写入白名单 `headers`,只保留 `cache-control`、`etag`、`last-modified`、`accept-ranges`、`content-range`、`content-length` 和 `content-encoding`,方便切换后复盘缓存和 Range 响应头。若发现 Vite 指纹资源,还会额外确认 `Cache-Control: public, max-age=31536000, immutable` 及其 GET / HEAD / 304 / Range method/path/status 证据,避免旧 tab chunk 缓存口径在直连后退化。direct live 的 HTTPS / HTTP base URL、Host、redirect Host、probe token、额外 path、SpacetimeDB 数据库名、access log 路径、timeout 和布尔 env 都不能包含换行或 NUL;脚本会在发起 HTTPS / HTTP / WSS 请求前失败,避免污染参数进入请求头、URL、日志对账或 JSON 证据。环境变量示例见 `deploy/env/pingora-direct-live.env.example`。生产证书必须可被系统信任;`--insecure-tls` 只允许本机自签证书 smoke 使用。`--skip-wss` 只允许单独 direct live 临时排障,release readiness `--require-direct` 会直接拒绝。 生产发布包默认不携带 Pingora,避免现有 API 流水线被影子网关构建依赖影响。需要部署影子服务时,构建机先确保有 `cmake`、C/C++ 编译器和 Rust target,再显式执行;`build-production-release.sh` 会在真实构建 Pingora 前 fail-fast 检查 `cmake`、C 编译器和 C++ 编译器,Jenkins `INCLUDE_PINGORA_GATEWAY=true` 时也会先检查这些工具: diff --git a/scripts/check-pingora-direct-live.mjs b/scripts/check-pingora-direct-live.mjs index a52a70937..b9a8f7659 100644 --- a/scripts/check-pingora-direct-live.mjs +++ b/scripts/check-pingora-direct-live.mjs @@ -331,7 +331,7 @@ async function main() { { name: 'https-spacetime-identity', url: joinUrl(config.httpsBaseUrl, '/v1/identity'), - expectedStatuses: [200, 401, 403, 404, 503], + expectedStatuses: [200, 401, 403, 404, 405, 503], assertHeader: assertPingoraGatewayHeader, }, {