55df19da9f
记录 dev 持久 shadow service 真实链路验收结果 记录 dev Nginx 前缀 canary 验收和恢复状态 补充 canary 前必须先完成持久 shadow 验收的口径
94 lines
24 KiB
Markdown
94 lines
24 KiB
Markdown
# Genarrative Nginx compression policy
|
||
|
||
本配置片段由 `scripts/jenkins-server-provision.sh` 在安装 Nginx 站点配置时展开。
|
||
|
||
## 请求体大小
|
||
|
||
- 生产、开发服和容器模板都在通用 `location ~ ^/api(?:/|$)` 内设置 `client_max_body_size 64m`。
|
||
- 该值只用于让携带参考图 Data URL 的创作接口抵达 `api-server`;不要把它当作业务上传上限。Rust 路由仍通过 `DefaultBodyLimit` 和解码后字节校验限制具体接口,例如拼图参考图路由只放宽到 12 MiB 请求体,图片字节继续按业务规则拒绝。
|
||
- 若线上看到 `413 Request Entity Too Large`,并且 access log 里 `request_time=0.000 upstream_status=-`,通常是 Nginx 没有加载该模板或未 reload;先执行 `nginx -T | grep client_max_body_size` 和 `nginx -t` 再检查 `api-server`。
|
||
|
||
## gzip
|
||
|
||
- `deploy/nginx/genarrative.conf` 与 `deploy/nginx/genarrative-dev-http.conf` 默认开启 gzip。
|
||
- 覆盖 `application/json`,用于降低 `/api/runtime/*/gallery` 这类 JSON 列表接口的公网带宽占用。
|
||
- 当前推荐等级为 `gzip_comp_level 5`,兼顾 2C/2G 服务器 CPU 与压缩收益。
|
||
- Pingora 影子网关已通过 `GENARRATIVE_PINGORA_GATEWAY_COMPRESSION_ALGORITHMS=gzip`、`GENARRATIVE_PINGORA_GATEWAY_GZIP_ENABLED=true`、`GENARRATIVE_PINGORA_GATEWAY_GZIP_LEVEL=5` 与 `GENARRATIVE_PINGORA_GATEWAY_GZIP_MIN_LENGTH_BYTES=1024` 承接 gzip parity;网关会把压缩算法收敛到 gzip allowlist,并按 `gzip_min_length 1024` 避免压缩小响应,同时沿用 Nginx `gzip_types` 边界不压缩图片资源。改动后必须运行 `npm run check:pingora-gateway-smoke` 验证小响应不压缩、图片资源不压缩,以及 `Accept-Encoding: gzip` 和 `Accept-Encoding: br, gzip` 的大响应都返回 gzip。
|
||
|
||
## Brotli
|
||
|
||
- Brotli 只在目标服务器 Nginx 接受 brotli 指令时开启。
|
||
- Pingora 当前正式化口径固定为 gzip-only,不承接 Brotli;做 Nginx -> Pingora canary 时,Brotli 仍由 Nginx 或更前置代理决定是否启用。直连 Pingora 时,不把 Brotli parity 作为切换门禁,避免使用 Pingora 0.8.1 里尚未通过可解压端到端验证的 Brotli compressor 路径。
|
||
- Ubuntu / apt 系统的 `Genarrative-Server-Provision` 会安装 `libnginx-mod-http-brotli-filter` 与 `libnginx-mod-http-brotli-static`;非 apt 系统暂不自动安装,仍按下面的能力探测结果决定是否启用。
|
||
- Provision 脚本通过临时配置执行 `nginx -t` 做能力探测;探测配置会先 `include /etc/nginx/modules-enabled/*.conf`,避免 Ubuntu 动态模块已安装但测试配置未加载模块导致误判。可用时把模板中的 `# __GENARRATIVE_BROTLI_DIRECTIVES__` 替换为 brotli 指令,不可用时保留注释说明。
|
||
- 不要直接在静态模板里无条件写 `brotli on;`,否则没有 brotli 模块的服务器会 `nginx -t` 失败并回滚。
|
||
- 不要用 `nginx -V | grep brotli` 判断 brotli 是否可用;Ubuntu apt 安装的 brotli 是动态模块,不会出现在普通编译参数里。应检查包、`/etc/nginx/modules-enabled/` 的 `load_module` 配置,或用包含 `include /etc/nginx/modules-enabled/*.conf` 的临时配置执行 `nginx -t`。
|
||
|
||
## Pingora upstream timeouts
|
||
|
||
- Pingora 影子网关已显式配置上游连接 / 读 / 写 timeout,避免正式 canary 时依赖 Pingora 默认值。
|
||
- 默认连接超时为 `3000ms`;没有 Nginx 显式长超时的代理路由读取超时为 `60s`。
|
||
- 通用 `/api`、公开列表 / 详情和 SpacetimeDB subscribe 读取超时为 `3600s`,写上游超时为 `3600s`,对齐当前 Nginx `proxy_read_timeout` / `proxy_send_timeout` 口径。
|
||
- 超时会返回 JSON `504 GATEWAY_UPSTREAM_TIMEOUT`,由 `npm run check:pingora-gateway-smoke` 覆盖。
|
||
|
||
## Pingora static cache policy
|
||
|
||
- Pingora 直连静态响应会显式写入 `Cache-Control`,避免公网入口切换后 HTML 入口页或 Vite 指纹资源依赖框架默认头。
|
||
- 默认 `GENARRATIVE_PINGORA_GATEWAY_HTML_CACHE_CONTROL=no-cache`,覆盖 `index.html`、`admin/index.html`、目录 index 和 SPA fallback。
|
||
- 默认 `GENARRATIVE_PINGORA_GATEWAY_ASSET_CACHE_CONTROL=public, max-age=31536000, immutable`,只覆盖 `/assets/*` 与 `/admin/assets/*` 中带 Vite 指纹文件名的资源;非指纹静态和 ACME challenge 默认 `GENARRATIVE_PINGORA_GATEWAY_STATIC_CACHE_CONTROL=no-cache`。
|
||
- Pingora 静态响应同时写入弱 `ETag`、`Last-Modified` 与 `Accept-Ranges: bytes`,并对 `If-None-Match` / `If-Modified-Since` 返回 `304`;这层只负责浏览器协商缓存,不改变上面的 `Cache-Control` 分档。
|
||
- Pingora 静态文件支持单段 `Range: bytes=`:合法范围返回 `206` 与 `Content-Range`,越界范围返回 `416` 与 `Content-Range: bytes */<len>`,`HEAD + Range` 只返回头。多段 range 暂按完整文件返回,不启用 multipart 响应。`If-Range` 日期匹配时继续返回局部内容,日期旧于文件或弱 ETag 校验器时回完整 `200`。`206` / `304` / `416` 均不做 gzip 压缩,避免局部内容语义和 `Content-Range` 漂移。
|
||
- Pingora 静态路由只允许 `GET` / `HEAD`。非读取方法命中静态候选时返回 `405` 与 `Allow: GET, HEAD`;缺失文件仍返回 `404`,避免错误客户端把静态入口当作可写接口。
|
||
- `npm run check:pingora-gateway-smoke` 会用固定 `X-Request-Id` 对账静态 `304` / `405` / `206` / `416` 的 Pingora access log 行,并同时校验 method / path / status;该 smoke 还会让 direct live 自动发现首页里的普通静态资源和 Vite 指纹资源,确认指纹资源 GET / HEAD / `If-None-Match` 304 / `Range: bytes=0-0` 以及 `public, max-age=31536000, immutable` 缓存头,确保本地静态响应状态和指纹 chunk 长缓存都可进入直连切换证据链。direct live JSON 只给静态 GET / HEAD / 304 / Range 写入白名单 `headers`,包括 `cache-control`、`etag`、`last-modified`、`accept-ranges`、`content-range`、`content-length` 和 `content-encoding`,便于证据包归档后复盘静态缓存与 Range 响应头。
|
||
|
||
## Pingora TLS / redirect
|
||
|
||
- Pingora 网关默认仍只监听本机 shadow 端口,不绑定公网 `80/443`。
|
||
- 需要评估直连入口时,显式配置 `GENARRATIVE_PINGORA_GATEWAY_TLS_LISTEN`、`GENARRATIVE_PINGORA_GATEWAY_TLS_CERT_FILE` 和 `GENARRATIVE_PINGORA_GATEWAY_TLS_KEY_FILE`;网关只读取现有证书文件,不负责 Certbot / ACME 自动续期。
|
||
- 需要 HTTP 到 HTTPS 跳转时,再显式配置 `GENARRATIVE_PINGORA_GATEWAY_HTTP_REDIRECT_LISTEN`;该入口除 `/.well-known/acme-challenge/*` 外统一 301 到 HTTPS,ACME challenge 仍从 `GENARRATIVE_PINGORA_GATEWAY_ACME_ROOT` 精确读取。
|
||
- 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;真实 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>`,脚本会隐藏 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。
|
||
- `npm run check:pingora-cutover-status-snapshot` 会烟测状态快照脚本,`npm run check:pingora-cutover-evidence-bundle` 会烟测证据包脚本;正式切换窗口与 release readiness 使用 `/opt/genarrative/current/scripts/ops/pingora-cutover-evidence-bundle.mjs` 归档切换前 / 启用后 / 回退后三个阶段的 `manifest.json`、`snapshot.json`、stdout / stderr 和命令记录。直连 runbook 的三个证据包阶段都会向状态快照透传 `--require-pingora-gateway`,在 `checks.current-release-audit` 中保存 Pingora 二进制、sha256、release manifest 和 systemd `ExecStart` 自审结果;启用后证据包还会通过 `--run-direct-live` 保存 `direct-live.json`、direct live stdout / stderr、命令记录、Pingora access log `request_id` 反查结果,以及静态响应头白名单证据。`manifest.summary.directLiveAccessLog` 会提升 checked / matched / missing / mismatch 对账摘要,`manifest.summary.directLiveStaticHeaders` 会提升普通静态和 Vite 指纹静态的缓存头、校验头、Range `Content-Range` 和 304 状态摘要,便于值班人员不打开 `direct-live.json` 也能先判断证据是否完整;如果 direct live 已输出静态资产结果但摘要缺少缓存头、校验头、Range `206 + Content-Range`、ETag 304 或 Last-Modified 304 证据,证据包会记为 `CRITICAL`。最终总审计还会带 `--require-phase-direct-live-access-log post-enable --require-phase-direct-live-static-headers post-enable`,防止缺少 access log 对账摘要或静态头摘要的旧启用后证据包混入正式归档。快照脚本只读采集状态,证据包脚本只写指定证据目录,不写 `/etc`、不 reload systemd,也不修改 Nginx 或 Pingora。
|
||
- 最终证据根目录总审计 JSON 先看 `summary.status`、`summary.failedItems[]` 和 `summary.directLiveEvidence[]`:失败时这里会直接指出阶段 / 命令 / 根目录问题,以及 `post-enable` access log 或静态头摘要的短 reason;`phases[]`、`commands[]` 和 `timeline` 继续作为完整机器归档。
|
||
- 最终证据根目录总审计必须同时带 `--require-command-executable enable-apply:pingora-direct-enable-apply:/opt/genarrative/current/scripts/deploy/pingora-direct-enable.sh` 和 `--require-command-executable rollback-apply:pingora-direct-rollback-apply:/opt/genarrative/current/scripts/deploy/pingora-direct-rollback.sh`,避免只证明有命令证据,却没有证明真实执行的是 current release 随包 enable / rollback 脚本。
|
||
- `npm run check:production-api-release` 会动态生成 API release,并检查发布包 README 与随包 `scripts/check-pingora-release-readiness.mjs --dry-run-cutover` 输出的最终总审计步骤都保留上述两条 `--require-command-executable` 要求,避免源码文档正确但发布包操作口径漂移。
|
||
- 直连接管后用 `node -- /opt/genarrative/current/scripts/deploy/pingora-health-patrol-env-switch.mjs --apply --env-file /etc/genarrative/health-patrol.env --gateway-mode pingora-direct --public-base-url <直连HTTPS入口> --public-host <域名>` 切换 health patrol env;该脚本只改 gateway mode、public base URL 和 public Host,并先用临时目标 env 调用随包 `check-production-health-patrol-env.mjs` 复核,复核通过后才原子替换真实 env,复核失败不会落盘。回退到 Nginx 前用同一脚本改回 `--gateway-mode nginx --public-base-url <切换前Nginx巡检入口>`,若切换前 Nginx 巡检不需要 Host 覆盖则传 `--clear-public-host`,需要 Host 覆盖则传 `--public-host <切换前Host>`;随后 rollback 脚本和独立 env 复核会再次阻断 public base URL / Host 漂移。`plan:pingora-direct-cutover` 会在 JSON runbook 中列出 direct / nginx 两个方向的 env 切换脚本和 env 复核步骤,并先输出 Host 与回退巡检入口确认;正式切换 runbook 会拒绝 `--direct-redirect-host` 或 `--rollback-nginx-smoke-host` 与 `--direct-host` 使用不同 hostname,且必须提供 `--rollback-health-patrol-public-base-url <切换前Nginx巡检入口>`,确认步骤会展示回退后要恢复的 public base URL / Host,避免回退计划把现场巡检入口覆盖成仓库默认值。若切换计划希望回退后同时证明 Pingora shadow 高端口仍健康,可给 runbook 追加 `--rollback-pingora-shadow-probe-url http://127.0.0.1:18081/__genarrative_pingora/healthz --rollback-pingora-shadow-probe-token <token>`;JSON 输出会隐藏 token 原文,并把对应参数传给 rollback dry-run / apply 步骤。
|
||
|
||
## Pingora canary
|
||
|
||
- `deploy/nginx/snippets/genarrative-pingora-canary.conf` 是默认不启用的人工前缀 canary 入口,只在需要验证 Nginx -> Pingora handoff 时临时 include。它使用 `/__genarrative_pingora_canary/` 前缀改写后转发到 `127.0.0.1:18081`,并返回 `X-Genarrative-Nginx-Handoff: pingora-canary`。
|
||
- `deploy/nginx/snippets/genarrative-pingora-realpath-canary.conf` 是前缀 canary 之后、direct 直连之前的真实路径 canary。它只能在 Nginx `http` 上下文人工 include,默认监听 `127.0.0.1:18083`,覆盖 `/api/creation-entry/config`、`/v1/identity`、`/v1/database/<db>/subscribe`、`/assets/app.js` 和拒绝入口,并写入独立 `/var/log/nginx/genarrative-pingora-realpath-canary.access.log`;不要把它 include 到生产 `443` server 内作为 location 覆盖。
|
||
- 启用 Nginx canary 前,目标机必须已经有持久 `genarrative-pingora-gateway.service` 运行在 `127.0.0.1:18081`,且带真实 `api-server`、SpacetimeDB、静态目录和 `/var/log/genarrative/pingora-gateway.access.log` 完成本机 shadow 验收;不要从一次性 `/tmp` 网关进程直接切到 Nginx handoff。
|
||
- 启用前必须运行 `npm run check:nginx-pingora-canary`;目标 agent 有 Nginx 时运行 `node scripts/check-nginx-pingora-canary.mjs --require-nginx`,同时做两个 snippet 的静态护栏和真实 `nginx -t`。本机或 CI 可运行 `npm run check:pingora-canary-docker`,用 Docker Nginx、真实 Pingora 和 mock 上游复现前缀 canary 与真实路径 canary 两条 handoff 链路。
|
||
- 前缀 canary reload 后运行 `GENARRATIVE_PINGORA_CANARY_BASE_URL=http://127.0.0.1 GENARRATIVE_PINGORA_CANARY_HOST=<域名> npm run check:pingora-canary-live`,再用 `scripts/check-pingora-canary-access-log-parity.mjs` 对账 `/var/log/nginx/genarrative.access.log` 与 `/var/log/genarrative/pingora-gateway.access.log`。
|
||
- 真实路径 canary reload 后运行 `node scripts/check-pingora-canary-live.mjs --realpath --base-url http://127.0.0.1:18083 --host <域名>`,再运行 `node scripts/check-pingora-canary-access-log-parity.mjs --realpath --nginx-log-file /var/log/nginx/genarrative-pingora-realpath-canary.access.log --pingora-log-file /var/log/genarrative/pingora-gateway.access.log --path /__genarrative_pingora_realpath_canary/healthz --path /api/creation-entry/config --path /v1/identity --path /assets/app.js`。真实路径模式除 healthz 探针外要求 Nginx path 与 Pingora path 完全一致。
|
||
- 正式切换前在源码 checkout / CI / 构建环境跑 `node scripts/check-pingora-release-readiness.mjs --require-docker --pull-docker --require-nginx --require-live --live-base-url http://127.0.0.1 --live-host <域名> --live-nginx-access-log /var/log/nginx/genarrative.access.log --live-pingora-access-log /var/log/genarrative/pingora-gateway.access.log`;启用真实路径 canary 时追加 `--require-realpath-live --realpath-live-base-url http://127.0.0.1:18083 --realpath-live-host <域名> --realpath-live-nginx-access-log /var/log/nginx/genarrative-pingora-realpath-canary.access.log --realpath-live-pingora-access-log /var/log/genarrative/pingora-gateway.access.log`。
|
||
- 目标机 `/opt/genarrative/current` 只能跑随包 runtime-only 门禁:`/opt/genarrative/current/scripts/check-pingora-release-readiness.mjs --release-runtime-only --require-live --live-base-url http://127.0.0.1 --live-host <域名> --live-nginx-access-log /var/log/nginx/genarrative.access.log --live-pingora-access-log /var/log/genarrative/pingora-gateway.access.log`;验证真实路径 canary 或 Pingora 直连入口时分别追加 `--require-realpath-live ...` 或 `--require-direct ...` 参数。生成正式直连切换 runbook 时,`--direct-redirect-host` 和回退 smoke Host 必须与 `--direct-host` 同 hostname,只允许端口不同。
|
||
|
||
## 验证
|
||
|
||
```bash
|
||
dpkg -l 'libnginx-mod-http-brotli-*'
|
||
ls -l /etc/nginx/modules-enabled/*brotli*
|
||
nginx -T 2>/dev/null | grep -Ei 'brotli|load_module'
|
||
|
||
curl -sSI -H 'Accept-Encoding: gzip' \
|
||
http://<host>/api/runtime/puzzle/gallery \
|
||
| grep -iE 'content-encoding|vary|content-type|content-length'
|
||
|
||
curl -sSI -H 'Accept-Encoding: br' \
|
||
http://<host>/api/runtime/puzzle/gallery \
|
||
| grep -iE 'content-encoding|vary|content-type|content-length'
|
||
```
|
||
|
||
预期:
|
||
|
||
- gzip 可用时返回 `Content-Encoding: gzip`。
|
||
- br 可用时返回 `Content-Encoding: br`。
|
||
- 响应头应包含 `Vary: Accept-Encoding`。
|