小巧到可以在任何地方运行
GoModel 是一个没有运行时依赖的单一静态 Go 二进制文件。它使用CGO_ENABLED=0 构建,并基于 distroless/static 发布,
因此容器中没有 shell、没有包管理器,也没有需要打补丁的 libc。
以上数据来自基准测试页面,是在相同硬件上与其他网关对比测得的。
实际意义在于,GoModel 可以轻松运行在对体积和冷启动有要求的环境中:Cloud Run、Fargate、Container Apps、Fly.io、容器化 Lambda,
或与您的应用部署在同一台小型虚拟机上。它不需要专用的节点池。
选择存储后端
GoModel 通过STORAGE_TYPE 持久化审计日志、用量记录、预算、虚拟模型、托管 API 密钥及其他管理状态。
SQLite 是默认选项,使 GoModel 无需任何配置即可运行;对于挂载了持久卷的单实例,它也是真正可用于生产环境的选择。
它省去了一次网络跳转,也少了一个需要运维的组件。
在两种情况下它不再适用:多于一个副本,以及文件系统在重启后无法保留的任何运行时。两个 SQLite 副本不会共享数据库,
而是各自拥有自己的数据库,因此用量、预算和托管 API 密钥会悄无声息地出现分歧。在一个 Pod 上创建的密钥在另一个 Pod 上并不存在。
此外,SQLite 在设计上只使用单个打开的连接,以保持单一写入者并避免锁竞争。每次审计日志刷新、用量刷新和预算检查都要通过它串行执行,
这在持续负载下会成为吞吐量上限。
对于 Postgres,
POSTGRES_MAX_CONNS 默认为 10。如果您在启用预算或速率限制的情况下运行高并发负载,请首先调高该值。
如果二进制文件旁已存在 ./data 目录,默认 SQLite 路径为 ./data/gomodel.db;否则使用操作系统的用户数据目录。
这使得默认路径依赖于工作目录,因此在生产环境中请显式设置 SQLITE_PATH。解析后的路径会在启动时以
storage configured 打印出来。请参阅 GoModel 将数据存储在哪里?。
Redis
Redis 是可选的。它用于支撑共享的模型目录快照和精确响应缓存。没有 Redis 时,GoModel 使用进程内缓存加本地文件缓存, 这种方式是正确的,但不会在副本之间共享。当多个副本需要共享模型发现结果和缓存命中时,请添加 Redis。如果配置了 Redis 模型缓存,而 Redis 在启动时不可达,网关将无法启动。之后与 Redis 断开连接只会导致降级状态。
在安排服务启动顺序时请考虑这一点。
提供商凭据
GoModel 可以从环境变量、config.yaml 或控制台的 Providers 页面获取提供商凭据。三种方式都可行,但风险并不相同。
在生产环境中,请通过环境变量配置提供商,并由您的 Secret(密钥)管理器提供这些值。 可以使用 AWS Secrets Manager、
Google Secret Manager、Azure Key Vault、HashiCorp Vault,或由 External Secrets Operator 或 Secrets Store CSI driver
填充的 Kubernetes Secret 来注入它们。
原因有两个,而第二个常常被忽视。
Secret 不会进入数据库。 从控制台保存的提供商凭据会持久化到 provider_credentials 存储中,MCP 服务器请求头和护栏 Secret
也会持久化到各自的存储中。除非设置了 GOMODEL_ENCRYPTION_KEY,否则它们以明文存储:*** 掩码仅在读取路径上应用,
因此任何拿到数据库文件、备份、快照或只读副本的人都能读取存储的值。设置密钥后,它们会被静态加密(请参阅静态数据加密),
但此时需要保护并妥善保存该密钥。通过环境变量或 config.yaml 声明的凭据则根本不会写入存储。
在配置中声明的提供商无法在运行时编辑。 在环境变量或 config.yaml 中声明的提供商在控制台中为只读。而存储在数据库中的提供商,
任何持有具备控制台权限的密钥的人都可以编辑,包括其 base_url。将 base_url 改指向攻击者控制的主机,会悄无声息地把每条提示词和注入的上游密钥都重定向过去。
以代码方式声明提供商意味着此类变更只能通过您的部署流水线进行。
如果您的 Secret 工具以文件形式挂载,请使用 Secret 引用将设置指向该文件,而不是将其复制到环境变量中:
GOMODEL_ENCRYPTION_KEY,并且仍应将数据库视为敏感数据:加密卷、限制访问,并对备份进行相应分级。
其他凭据处理
- 托管 API 密钥以高熵随机 Secret 的 SHA-256 哈希形式存储,永远无法还原。明文仅在创建时显示一次。这与提供商凭据的处理方式刻意不同。
- 客户端凭据请求头在持久化之前会被脱敏。 当设置
LOGGING_LOG_HEADERS=true时,Authorization、x-api-key、Cookie及其他凭据请求头会在写入路径上被替换为[REDACTED],因此审计存储永远不会收到它们。 - 设置
GOMODEL_MASTER_KEY。 如果它为空且不存在任何托管密钥,所有请求都会在未经认证的情况下放行,并且/admin/*会被加入认证跳过列表,作为锁定后的恢复路径。处于这种状态且可从互联网访问的网关,会把完整的 Admin API 交给任何人。
TLS
GoModel 不负责终止 TLS。它提供纯 HTTP 服务,并期望前面部署反向代理或负载均衡器。对于任何不仅限于回环地址的部署,都请部署一个: 否则客户端 API 密钥、托管网关密钥和主密钥都会以明文在网络上传输。 此外,GoModel 没有 CORS 中间件,因此其他源上的浏览器客户端无法直接调用网关。如有需要,请在代理上添加相应的响应头。私有 CA 签发的上游证书
出站 HTTPS(提供商和 MCP 服务器)会使用系统 CA 证书包进行校验。容器镜像已包含该证书包(/etc/ssl/certs/ca-certificates.crt),
因此公共端点无需任何设置。
如果上游证书由内部或企业 CA 签发,连接会失败并报 x509: certificate signed by unknown authority。请将 CA 证书挂载到受信任目录中,
GoModel 会在公共根证书之外额外读取该目录:
SSL_CERT_FILE 同样可用,但它会替换证书包文件而不是向其中追加,因此请将其指向一个同时包含您所需公共根证书的证书包。
离线隔离与离线部署
GoModel 可以在完全离线隔离(air-gapped)的环境中运行。 没有遥测、没有分析,也没有许可证检查。管理控制台内嵌在二进制文件中, 其字体也已随附,因此界面不会加载任何 CDN 资源。搭配 Ollama、SGLang 或 vLLM 等本地模型服务器时,网关无需任何通往公共互联网的路由。 默认情况下,网关只会发出两种不面向已配置提供商的出站调用,一个开关即可同时关闭两者:GOMODEL_OFFLINE=true(或 config.yaml 中的 offline: true)会禁用更新检查,并丢弃所有 HTTP 目录 URL。它在所有其他设置之后应用,
因此 config.yaml 或环境变量中的任何内容都无法在其之下重新启用出站调用。对已配置提供商的调用,以及对您自行声明的任何服务
(例如 OTLP 采集器、MCP 上游或向量存储)的调用不受影响。启动日志会确认该模式。
您也可以通过 GOMODEL_VERSION_CHECK_ENABLED=false 和 MODEL_LIST_URL=off 分别控制这两种调用。
目录获取是尽力而为的。当它被关闭或失败时,网关会正常启动,/health 和 /health/ready 返回 200,提供商模型发现仍然有效,
因为模型列表来自各提供商自己的 /models 端点,请求也会正常路由。您失去的是元数据补充。
在离线隔离环境中保留定价有以下三种方式:
-
以文件形式提供目录。 在隔离环境之外下载
models.min.json,复制进来,并将网关指向它。本地文件只会被读取而不会被下载, 因此在GOMODEL_OFFLINE=true下依然有效:每次缓存刷新时都会重新读取该文件,因此在磁盘上替换它即可更新定价,无需重启。 -
建立镜像。 在内部 HTTP 主机上提供该文件,并将
MODEL_LIST_URL设置为该 URL。不要设置GOMODEL_OFFLINE, 并单独禁用更新检查,或者同样将GOMODEL_VERSION_CHECK_URL指向内部镜像。 -
在
config.yaml的providers.<name>.models[].metadata.pricing下按模型声明定价。
将
MODEL_LIST_URL 设置为空字符串不会禁用下载:空的环境变量值会被跳过,因此默认 URL 依然生效。请使用 off 或 GOMODEL_OFFLINE=true。169.254.169.254)以获取凭据。离线隔离安装通常不会配置
Bedrock,但了解这一点仍有必要。
运行多个副本
请求处理是无状态的,因此普通流量不需要副本亲和性。不过,有若干功能会将状态保存在进程内存中,且不会在实例之间协调。
最容易让人意外的是速率限制:它是进程内控制,因此三个副本配合 100 rpm 的规则,总计最多可放行 300 rpm。请按单个副本设定规则,
并使用预算作为持久化的跨实例控制,因为预算从共享数据库中读取。
配置变更不会立即传播
管理端托管的配置持久化在数据库中,但每个副本都是从内存快照中提供服务的。在控制台中保存的变更会立即更新处理该请求的副本。 其他副本按各自的刷新节奏获取变更,其中有两类配置根本没有刷新机制。健康探测与关闭
GoModel 分别提供存活和就绪检查,二进制文件还可以自我探测,这在没有 shell 或curl 的 distroless 镜像中同样适用。
请将 Kubernetes 就绪探针指向
/health/ready,而不是 /health。仓库 helm/ 目录中的 Helm chart 已经这样配置,它会以镜像的非 root
用户在只读文件系统上运行网关,将 SQLite 保存在持久卷上,并且在您将 storage.type 切换为 postgresql 或 mongodb 之前拒绝多于一个副本。
相关取值请参阅 helm/README.md。
就绪检查不会等待模型目录加载完成,目录是异步加载的。新的 Pod 可能在
GET /v1/models 仍为空时就报告就绪,导致最初的请求失败。
请在发布设置中考虑这一点,或在切换流量之前预热 Pod。SIGTERM 后,网关会用 10 秒排空进行中的 HTTP 工作,然后在 30 秒内完成清理,并在退出过程中刷新缓冲的用量和审计条目。
这两个超时都不可配置。进行中的流式响应会在第 10 秒时被中断,因此滚动部署期间正在进行的长补全会被截断。请将
terminationGracePeriodSeconds 设置为大于 30(45 是一个合理的选择),以免清理过程与 SIGKILL 竞争。
数据保留与磁盘增长
审计日志和用量追踪会为每个请求写入一行,并且两者每小时清理一次。
在大流量下还有两点需要注意:
- 当缓冲区写满时,用量和审计写入会被丢弃,而不是阻塞。 突发流量或缓慢的数据库可能会悄无声息地丢失用量条目,
这意味着成本数据丢失和预算扣费不足。唯一的信号是日志中的
usage log buffer full警告,因此请针对它设置告警。 - 预算检查会在每个请求上查询用量表。 启用预算时请将
USAGE_RETENTION_DAYS设置得尽量小,并优先使用 Postgres 而非 SQLite, 因为 SQLite 的单连接会使这部分成为主要开销。
可观测性
- 指标默认关闭。 设置
METRICS_ENABLED=true可在METRICS_ENDPOINT(/metrics)暴露 Prometheus 指标。该端点无需认证, 因此请将其保留在您的网络边界之内。请参阅 Prometheus 指南。 - OpenTelemetry 导出默认关闭。 设置
OTEL_ENABLED=true和OTEL_EXPORTER_OTLP_ENDPOINT,即可将 Trace 和 GenAI 指标发送到您的采集器。 请参阅 OpenTelemetry 指南。 - 当 stdout 不是 TTY 时,日志会自动采用 JSON 格式,因此容器无需任何配置即可获得结构化日志。如需覆盖,请显式设置
LOG_FORMAT。LOG_LEVEL默认为info;无效值会导致启动失败。 gomodel_circuit_breaker_state是用于提供商健康告警的计量指标。它按请求更新,因此空闲的提供商会保持其最后一次观测到的值。- 流式响应的请求时长衡量的是建立流所需的时间,而不是整个流的持续时间。阅读流式延迟面板时请注意这一点。
- Prometheus 中没有 Token 或成本指标。 支出和 Token 统计保存在用量数据库、控制台和
GET /v1/usage中。 请基于预算而不是 Prometheus 设置支出告警。
安全加固说明
- 将管理入口置于您的网络边界之后。 控制台和
/admin/*与模型 API 在同一端口上提供服务,且无法迁移到单独的监听器。 请在代理或网络层面限制对它们的访问,或使用ADMIN_ENDPOINTS_ENABLED=false将其禁用。控制台外壳及其静态资源在设计上跳过认证; 只有它们加载的数据受到保护。 - 限制数据库文件的访问权限。 SQLite 数据目录以
0755创建,数据库文件使用默认权限,因此在共享主机上可能对所有人可读。 请以专用用户身份运行 GoModel 并收紧权限,尤其是在通过控制台存储了任何凭据的情况下。 - 将
BODY_SIZE_LIMIT保持在合理范围。 它默认为10M,用于防止超大请求体成为耗尽内存的攻击途径。无法解析的值会回退到默认值, 且只会给出一条警告,因此请检查拼写。 - 保持
STREAM_STALL_TIMEOUT开启。 它默认为60秒,当客户端打开流后停止读取时,它负责释放该客户端占用的 goroutine 和上游提供商连接。 禁用它(0)会让此类客户端一直占用这两者,直到提供商侧的HTTP_TIMEOUT到期。 - 保持
pprof禁用。 它默认关闭,开启时无需认证。 - 限定托管 API 密钥的作用域。 为每个使用方分配独立的密钥及其独立的用户路径,这也是实现按使用方速率限制和预算的前提。
仅在需要时授予
dashboard_access和passthrough_access。
生产环境检查清单
- 将
GOMODEL_MASTER_KEY设置为强密码值。 - 在网关前面的代理中终止 TLS。
- 在网络边界限制对
/admin/*、控制台和/metrics的访问。 - 多于一个副本或使用任何临时文件系统时,请使用 Postgres 或 MongoDB;使用 SQLite 时,请挂载卷并设置
SQLITE_PATH。 - 在环境变量或
config.yaml中声明提供商,其值来自 Secret 管理器。 - 运行多个副本时,以代码方式声明预算和速率限制,并按单个副本设定速率限制规则。
- 明确决定
LOGGING_LOG_BODIES的取值,并有意识地设置数据保留期。 - 将就绪检查指向
/health/ready,并将terminationGracePeriodSeconds设置为大于 30。 - 启用指标,并针对
gomodel_circuit_breaker_state和usage log buffer full设置告警。 - 对于离线隔离安装,请设置
GOMODEL_OFFLINE=true,然后以文件形式提供模型目录,或在配置中声明模型定价,以确保成本追踪和预算继续工作。