新增 Pingora 独立网关试点
新增 pingora-gateway 独立二进制 crate,复刻当前 Nginx 核心路由口径 接入 Pingora 依赖、workspace 成员和锁文件 补充 Pingora 影子网关运维文档、环境变量示例和 Hermes 决策记录
This commit is contained in:
@@ -1728,3 +1728,11 @@
|
||||
- 影响范围:`shared-contracts` 默认 spec、`module-runtime` 入口配置响应、`spacetime-module` 后台保存校验、后台入口开关页摘要和前端 fallback spec。
|
||||
- 验证方式:`GET /api/creation-entry/config` 中各玩法 `unifiedCreationSpec.title` 等于已保存契约内容;后台只修改入口名称时不应隐式改写已保存的统一创作页表头。
|
||||
- 关联文档:`docs/【玩法创作】平台入口与玩法链路-2026-05-15.md`。
|
||||
|
||||
## 2026-06-11 Pingora 网关先独立二进制试点
|
||||
|
||||
- 背景:评估 Pingora 是否逐步替代当前生产 Nginx 时,需要先验证 Genarrative 的现有反向代理、静态资源、维护模式和最小 SpacetimeDB 公网路由口径。
|
||||
- 决策:新增 `server-rs/crates/pingora-gateway` 作为独立 binary crate,默认监听 `127.0.0.1:18081` 做影子网关;当前不绑定 `80/443`,不替代 `deploy/nginx/genarrative.conf`,生产仍以 Nginx 为公网入口。
|
||||
- 影响范围:Rust workspace、Pingora 依赖、网关环境变量、`deploy/pingora/pingora-gateway.env.example` 和运维技术方案。
|
||||
- 验证方式:先执行 `cargo fmt --manifest-path server-rs/Cargo.toml -p pingora-gateway`、`cargo test -p pingora-gateway --manifest-path server-rs/Cargo.toml`;替换前必须补齐路由 parity、压缩、TLS、限流、systemd、Jenkins 和健康巡检。
|
||||
- 关联文档:`docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md`。
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# Pingora 独立网关试点配置示例。
|
||||
# 当前只用于本机影子验证,不绑定 80/443,也不替代生产 Nginx。
|
||||
|
||||
GENARRATIVE_PINGORA_GATEWAY_LISTEN=127.0.0.1:18081
|
||||
GENARRATIVE_PINGORA_GATEWAY_API_UPSTREAM=127.0.0.1:8082
|
||||
GENARRATIVE_PINGORA_GATEWAY_SPACETIME_UPSTREAM=127.0.0.1:3101
|
||||
|
||||
GENARRATIVE_PINGORA_GATEWAY_WEB_ROOT=/srv/genarrative/web
|
||||
GENARRATIVE_PINGORA_GATEWAY_ACME_ROOT=/var/www/html
|
||||
GENARRATIVE_PINGORA_GATEWAY_MAINTENANCE_FILE=/var/lib/genarrative/maintenance/enabled
|
||||
|
||||
GENARRATIVE_PINGORA_GATEWAY_FORWARDED_PROTO=http
|
||||
GENARRATIVE_PINGORA_GATEWAY_MAX_API_BODY_BYTES=67108864
|
||||
|
||||
GENARRATIVE_PINGORA_GATEWAY_LOG=info,pingora=info,pingora_gateway=info
|
||||
GENARRATIVE_PINGORA_GATEWAY_OTEL_ENABLED=false
|
||||
+1
-1
@@ -21,7 +21,7 @@
|
||||
|
||||
微信小程序虚拟支付接入、`wechat_mp_virtual` 渠道、`wx.requestVirtualPayment` 承接页和后端签名配置见 [【技术方案】微信虚拟支付接入-2026-05-26.md](./%E3%80%90%E6%8A%80%E6%9C%AF%E6%96%B9%E6%A1%88%E3%80%91%E5%BE%AE%E4%BF%A1%E8%99%9A%E6%8B%9F%E6%94%AF%E4%BB%98%E6%8E%A5%E5%85%A5-2026-05-26.md)。
|
||||
|
||||
生产部署切换到 systemd + Nginx + SpacetimeDB 自托管的总方案见 [PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md](./technical/PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md),该文档也是当前生产 Jenkinsfile 的唯一入口。SpacetimeDB 表结构变更、自动迁移边界和保留旧数据的分阶段迁移流程见 [SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md](./technical/SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md);private 表迁移 JSON 导入导出、HTTP 413 分片导入和旧数据库迁移流水线经验见 [SPACETIMEDB_JSON_STRING_MIGRATION_PROCEDURE_2026-04-27.md](./technical/SPACETIMEDB_JSON_STRING_MIGRATION_PROCEDURE_2026-04-27.md) 与 [JENKINS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md](./technical/JENKINS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md);后台管理独立前端工程技术方案见 [ADMIN_WEB_CONSOLE_TECHNICAL_SOLUTION_2026-04-30.md](./technical/ADMIN_WEB_CONSOLE_TECHNICAL_SOLUTION_2026-04-30.md)。
|
||||
生产部署切换到 systemd + Nginx + SpacetimeDB 自托管的总方案见 [PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md](./technical/PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md),该文档也是当前生产 Jenkinsfile 的唯一入口。Pingora 只作为独立二进制影子网关试点时,边界、路由口径与替换前验收见 [【开发运维】Pingora独立网关试点-2026-06-11.md](./technical/【开发运维】Pingora独立网关试点-2026-06-11.md)。SpacetimeDB 表结构变更、自动迁移边界和保留旧数据的分阶段迁移流程见 [SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md](./technical/SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md);private 表迁移 JSON 导入导出、HTTP 413 分片导入和旧数据库迁移流水线经验见 [SPACETIMEDB_JSON_STRING_MIGRATION_PROCEDURE_2026-04-27.md](./technical/SPACETIMEDB_JSON_STRING_MIGRATION_PROCEDURE_2026-04-27.md) 与 [JENKINS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md](./technical/JENKINS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md);后台管理独立前端工程技术方案见 [ADMIN_WEB_CONSOLE_TECHNICAL_SOLUTION_2026-04-30.md](./technical/ADMIN_WEB_CONSOLE_TECHNICAL_SOLUTION_2026-04-30.md)。
|
||||
|
||||
SpacetimeDB 表结构变更、自动迁移边界和保留旧数据的分阶段迁移流程见 [SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md](./technical/SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md)。
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
# Pingora 独立网关试点
|
||||
|
||||
## 目标
|
||||
|
||||
本试点新增 `server-rs/crates/pingora-gateway` 独立二进制 crate,用 Pingora 复刻当前生产 Nginx 的核心反向代理与静态路由口径。当前阶段只作为影子网关验证,不绑定公网 `80/443`,不替代 `deploy/nginx/genarrative.conf`。
|
||||
|
||||
## 运行边界
|
||||
|
||||
- 默认监听 `127.0.0.1:18081`,只用于本机或容器内 smoke。
|
||||
- 默认转发 `api-server` 到 `127.0.0.1:8082`。
|
||||
- 默认转发最小 SpacetimeDB 公网路由到 `127.0.0.1:3101`。
|
||||
- 默认静态目录为 `/srv/genarrative/web`,维护开关文件为 `/var/lib/genarrative/maintenance/enabled`。
|
||||
- 当前不承接 TLS、HTTP 到 HTTPS 跳转、gzip/Brotli、完整连接数限制、完整 RPS 限流、Certbot ACME 自动化、Jenkins 产物发布和 systemd 健康巡检。
|
||||
|
||||
## 启动命令
|
||||
|
||||
本机影子验证时先启动 SpacetimeDB 与 `api-server`,再运行:
|
||||
|
||||
```bash
|
||||
GENARRATIVE_PINGORA_GATEWAY_WEB_ROOT=/srv/genarrative/web \
|
||||
cargo run -p pingora-gateway --manifest-path server-rs/Cargo.toml
|
||||
```
|
||||
|
||||
也可以复制 `deploy/pingora/pingora-gateway.env.example` 到部署环境的非 Git 配置文件,由 systemd 或容器注入。
|
||||
|
||||
## 环境变量
|
||||
|
||||
| 变量 | 默认值 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `GENARRATIVE_PINGORA_GATEWAY_LISTEN` | `127.0.0.1:18081` | Pingora 监听地址。 |
|
||||
| `GENARRATIVE_PINGORA_GATEWAY_API_UPSTREAM` | `127.0.0.1:8082` | `api-server` 上游地址。 |
|
||||
| `GENARRATIVE_PINGORA_GATEWAY_SPACETIME_UPSTREAM` | `127.0.0.1:3101` | SpacetimeDB 上游地址。 |
|
||||
| `GENARRATIVE_PINGORA_GATEWAY_WEB_ROOT` | `/srv/genarrative/web` | 前端静态文件根目录。 |
|
||||
| `GENARRATIVE_PINGORA_GATEWAY_ACME_ROOT` | `/var/www/html` | ACME challenge 静态目录。 |
|
||||
| `GENARRATIVE_PINGORA_GATEWAY_MAINTENANCE_FILE` | `/var/lib/genarrative/maintenance/enabled` | 存在即进入维护模式。 |
|
||||
| `GENARRATIVE_PINGORA_GATEWAY_FORWARDED_PROTO` | `http` | 写入 `X-Forwarded-Proto` 的值。 |
|
||||
| `GENARRATIVE_PINGORA_GATEWAY_MAX_API_BODY_BYTES` | `67108864` | `/api` 通用路由的 `Content-Length` 上限。 |
|
||||
| `GENARRATIVE_PINGORA_GATEWAY_LOG` | `info,pingora=info,pingora_gateway=info` | tracing 过滤器。 |
|
||||
| `GENARRATIVE_PINGORA_GATEWAY_OTEL_ENABLED` | `false` | 是否启用共享 OpenTelemetry 初始化。 |
|
||||
|
||||
## 当前路由口径
|
||||
|
||||
| 路由 | 行为 |
|
||||
| --- | --- |
|
||||
| `/.well-known/acme-challenge/*` | 从 `GENARRATIVE_PINGORA_GATEWAY_ACME_ROOT` 精确读取静态文件。 |
|
||||
| `/admin` | 301 到 `/admin/`。 |
|
||||
| `/admin/api/*` | 转发到 `api-server`。 |
|
||||
| `/admin/assets/*` | 从 Web 根目录精确读取静态文件。 |
|
||||
| `/admin/*` | 先读取静态文件或目录 index,失败回退 `/admin/index.html`。 |
|
||||
| `/assets/*` | 从 Web 根目录精确读取静态文件。 |
|
||||
| `/api/runtime/puzzle/gallery`、`/api/runtime/custom-world-gallery` | 转发到 `api-server`。 |
|
||||
| `/api/runtime/puzzle/gallery/{id}`、`/api/runtime/custom-world-gallery/{profile}/{owner}` | 转发到 `api-server`。 |
|
||||
| `/api`、`/api/*` | 转发到 `api-server`,按配置执行 `Content-Length` 上限检查。 |
|
||||
| `/v1/database/{db}/subscribe`、`/v1/identity*` | 转发到 SpacetimeDB,保留 WebSocket Upgrade 头。 |
|
||||
| `/v1/*`、`/generated-*`、`/healthz*`、`/readyz*` | 返回 404,保持生产公网不暴露口径。 |
|
||||
| 其它路径 | 先读取静态文件或目录 index,失败回退 `/index.html`。 |
|
||||
|
||||
维护模式下,API-like 路由返回 JSON `503`,Web 静态路由优先返回 `maintenance.html`,不存在时返回纯文本 `503`。
|
||||
|
||||
## 后续替换前验收
|
||||
|
||||
1. 容器内使用同一份 Web 产物、同一组上游地址跑 Pingora smoke。
|
||||
2. 对照 `deploy/nginx/genarrative.conf` 做路由 parity 自动测试,覆盖 API、Admin、SPA fallback、静态资源、维护模式和 SpacetimeDB WebSocket。
|
||||
3. 补齐限流、连接数限制、压缩、TLS、ACME 和访问日志字段。
|
||||
4. 增加 systemd service 模板与健康巡检,但仍由 Nginx 反向代理到 Pingora 做 canary。
|
||||
5. canary 稳定后,再评估是否让 Pingora 直接承接公网入口。
|
||||
Generated
+952
-58
File diff suppressed because it is too large
Load Diff
@@ -40,6 +40,7 @@ members = [
|
||||
"crates/platform-wechat",
|
||||
"crates/platform-speech",
|
||||
"crates/platform-agent",
|
||||
"crates/pingora-gateway",
|
||||
"crates/shared-contracts",
|
||||
"crates/shared-kernel",
|
||||
"crates/shared-logging",
|
||||
@@ -87,6 +88,7 @@ platform-llm = { path = "crates/platform-llm", default-features = false }
|
||||
platform-oss = { path = "crates/platform-oss", default-features = false }
|
||||
platform-speech = { path = "crates/platform-speech", default-features = false }
|
||||
platform-wechat = { path = "crates/platform-wechat", default-features = false }
|
||||
pingora-gateway = { path = "crates/pingora-gateway", default-features = false }
|
||||
shared-contracts = { path = "crates/shared-contracts", default-features = false }
|
||||
shared-kernel = { path = "crates/shared-kernel", default-features = false }
|
||||
shared-logging = { path = "crates/shared-logging", default-features = false }
|
||||
@@ -111,6 +113,10 @@ image = { version = "0.25", default-features = false }
|
||||
jsonwebtoken = "9"
|
||||
langchainrust = "0.2.18"
|
||||
log = "0.4"
|
||||
mime_guess = "2.0.5"
|
||||
pingora = { version = "0.8.1", default-features = false, features = ["proxy"] }
|
||||
pingora-http = { version = "0.8.1", default-features = false }
|
||||
pingora-proxy = { version = "0.8.1", default-features = false }
|
||||
rand_core = "0.6"
|
||||
reqwest = { version = "0.12", default-features = false }
|
||||
ring = "0.17"
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "pingora-gateway"
|
||||
edition.workspace = true
|
||||
version.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
async-trait = { workspace = true }
|
||||
bytes = { workspace = true }
|
||||
mime_guess = { workspace = true }
|
||||
pingora = { workspace = true }
|
||||
pingora-http = { workspace = true }
|
||||
pingora-proxy = { workspace = true }
|
||||
shared-logging = { workspace = true }
|
||||
tokio = { workspace = true, features = ["fs"] }
|
||||
tracing = { workspace = true }
|
||||
uuid = { workspace = true, features = ["v4"] }
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user