
10. 网关二进制与部署1. 背景与原理1.1 Gateway 在 SOVD 中的角色SOVD gateway 是聚合层把多个下游 SOVD server车内多个 ECU/HPC、或下层网关的实体汇聚成统一视图对外暴露单一/sovd/v1。它的特殊性在于无状态聚合结果来自下游重启后由发现机制重建可裁剪车载部署可能只要 TCP 无安全云端部署要 TLS JWT Rego CORS需与平台集成systemd socket activation、容器就绪探针、静态 Web UI 托管因此 gateway 是配置驱动的可执行产物——它把库的能力通过 CLI 参数暴露出来。1.2 为什么拆出libcligateway与mcp两个二进制共享tracing 初始化、trace layer、优雅关闭。抽成libcli避免重复也保证两者日志格式一致。2. 当前实现架构2.1 二进制与目录opensovd-cli/ ├── lib/ → crate libclitracing 初始化、trace tower layer ├── gateway/ → bin opensovd-gateway默认端口 7690 └── mcp/ → bin opensovd-mcpMCP over stdio2.2 CLI 参数矩阵gateway类别参数环境变量说明网络--urlSOVD_URL形如http://host:port/pathhost:port 用于 TCP 绑定path 作为 base URI--unix-socket—Unix socket 路径前缀为 Linux abstract socket指定时忽略 host:port数据--mock—启用opensovd-mocks示例拓扑--serve-dir PATH:DIR—挂载静态目录如/ui:./webui/dist安全--tls-cert/--tls-key/--tls-client-caSOVD_TLS_CERT/SOVD_TLS_KEYTLS 与 mTLS--auth-jwt-key/--auth-jwt-algo/--auth-jwt-issuer—JWTHS512/RS512密钥 base64--auth-policy/--auth-policy-data—Rego 策略与 JSON dataCORS--cors-origin/-method/-header/-credentials/-max-age—跨域配置平台systemd socket activationLinux—自动检测LISTEN_FDS2.3 构建期信息注入const VENDOR_INFO: OpenSovdInfo OpenSovdInfo { version: env!(CARGO_PKG_VERSION), sha1: env!(COMMIT_SHA), // ← build.rs 注入 build_date: env!(BUILD_DATE), // ← build.rs 注入 name: OpenSOVD, };build.rs依赖timecrate 生成构建时间戳与 commit sha随/version-info下发——现场可追溯部署版本这是车规运维的实用设计。2.4 部署形态形态支持容器docker/Dockerfile.gateway、Dockerfile.mcpGHCR 镜像ghcr.io/eclipse-opensovd/opensovd-gatewaysystemdsocket activation sd_notifyREADY裸机nightly/latest 滚动发布4 平台二进制linux x64/aarch64、macOS aarch64、Windows x64开发cargo run -p opensovd-gateway -- --mock、devcontainer、Nix flake3. 核心流程与算法3.1 启动流程main() ├─ Cli::parse() clap支持环境变量 ├─ libcli::init_tracing(gwinfo,srvinfo,tower_httpdebug,axumtrace) ├─ run(cli) │ ├─ 有 jwt_key? │ │ ├─ 是 → 构造 JwtAuthenticatorbase64 解码密钥 → 算法 → issuer │ │ │ 有 policy? → RegorusAuthorizer : AllowAll │ │ └─ 否 → NoAuth AllowAll │ └─ serve(cli, authenticator, authorizer) │ ├─ 解析 --url → base_uri(path) authority(host:port) │ ├─ configure_listenersystemd fd unix socket TCP bind │ ├─ configure_topology--mock ? create_mock_topology() : Topology::default() │ ├─ TLS 配置 │ ├─ CORS 层 trace 层 静态目录服务 │ ├─ .base_uri().vendor_info().build() │ ├─ notify_readiness() sd_notify READY1 │ └─ server.serve().await └─ ExitCode3.2 监听器选择的优先级算法// 1) Linux systemd socket activation最高优先级 #[cfg(target_os linux)] if let Some(fd) sd_notify::listen_fds()?.next() { let std_listener unsafe { std::net::TcpListener::from_raw_fd(fd) }; // SAFETY: fd 由 systemd 提供且被拥有 std_listener.set_nonblocking(true)?; return Ok(builder.listener(tokio::net::TcpListener::from_std(std_listener)?)); } // 2) --unix-socket支持 前缀的 abstract socket if let Some(ref socket_path) cli.unix_socket { ... } // 3) TCP bind(authority) let listener tokio::net::TcpListener::bind(authority).await?;优先级systemd fd Unix socket TCP。这个顺序符合平台托管 本地 IPC 网络的惯例。3.3 就绪通知fn notify_readiness() { #[cfg(target_os linux)] if let Err(e) sd_notify::notify([sd_notify::NotifyState::Ready]) { tracing::warn!(target: TARGET, error %e, Failed to notify systemd readiness); } }通知发生在serve()之前listener 已绑定——语义上是已绑定但严格来说应在 axum 开始 accept 之后。3.4 层叠顺序let server builder .layer(libcli::trace::trace_layer()) // 先加 → 最外层 .layer(tower::util::option_layer(cors)) .base_uri(base_uri)? .vendor_info(VENDOR_INFO) .build()?;最终栈trace → cors → (AuthN → AuthZ → router)。trace 在最外层可记录被 CORS/鉴权拒绝的请求。4. 待完善与风险4.1 部署正确性严重base_uri硬编码导致反向代理下链接错误高见 06 章 §4.3 缺陷 8。在 K8s Ingress / 反向代理后/sovd前缀与http://scheme 都会不符合实际。这是容器化部署最先遇到的问题。就绪通知时机偏早中sd_notify(READY)在 axum 开始 accept 之前发出K8s 可能在服务真正可用前就开始转发流量虽然窗口极小。建议在serve()内部或on_listening回调中通知。无健康检查端点中/version-info可勉强充当 liveness但没有 readiness/health 语义无法表达拓扑为空/发现失败等降级状态。无优雅关闭超时配置低axum 的 graceful shutdown 没有等待上限慢请求会无限延长关闭。4.2 配置与运维中密钥通过命令行传入中--auth-jwt-key会出现在ps输出与 shell history 中。建议支持从文件/环境变量/密钥管理服务读取虽有SOVD_TLS_*的环境变量先例但 JWT 密钥只支持命令行。无配置文件支持中参数众多20纯 CLI 难以管理缺少 YAML/TOML 配置与校验。无配置回显/启动时自检低启动日志会打印启用的特性TLS/CORS/JWT/Rego但不打印实际生效值如绑定的地址、base_uri排障不便。--serve-dir无路径穿越防护说明中serve_dir基于tower_http::fs需确认是否规范化..文档未说明。4.3 可观测性中无/metrics中无请求数、延迟、连接数、发现状态等指标。无 request id 贯穿中trace 层按 HTTP 维度记录但无跨层关联 ID。日志级别由硬编码字符串决定低init_tracing(gwinfo,srvinfo,tower_httpdebug,axumtrace)写死在代码中tower_httpdebug与axumtrace在生产会产生大量日志应可通过RUST_LOG覆盖需确认libcli是否支持 env 覆盖。4.4 发布与版本中只有滚动 tag中latest/nightly无 semver release、无 CHANGELOG生产环境无法锁定版本。镜像标签策略未文档化低GHCR 镜像与 git commit 的对应关系不清晰故障回溯困难虽有sha1编入vendor_info可缓解。4.5 建议的改进顺序优先级事项P0修复base_uri派生含 X-Forwarded-* 与 TLS scheme 推断P1就绪通知移到 accept 之后增加/healthz含发现状态P1JWT 密钥支持文件/环境变量注入P2配置文件支持 启动配置回显P2/metrics request idP2semver release CHANGELOG5. 关键代码位置内容路径main/run/serveopensovd-cli/gateway/src/main.rs:42-184VENDOR_INFO 与 build 注入opensovd-cli/gateway/src/main.rs:33-38、build.rs监听器选择opensovd-cli/gateway/src/main.rs:186-245拓扑配置mockopensovd-cli/gateway/src/main.rs:247-263就绪通知opensovd-cli/gateway/src/main.rs:265-270CLI 参数定义opensovd-cli/gateway/src/cli.rs:43-223CORS 层构造opensovd-cli/gateway/src/cors.rs静态目录服务opensovd-cli/gateway/src/serve_dir.rslibclitracing/layeropensovd-cli/lib/src/{lib.rs,trace.rs}容器docker/Dockerfile.gateway、docker/Dockerfile.mcpsystemd 示例examples/server/systemd/systemd.rs