运维

故障排查

诊断启动、产物、认证、权限和部署问题。

从症状出发,先检查最小的边界。

ObjectOS 无法启动

**先读日志的最后几行,再做别的。**这里有一大类启动失败是有意的拒绝,而不是 崩溃:运行时会检查它收到的配置,打印一条点名相互矛盾的变量的致命错误,然后退出。 这些消息会准确地指出问题所在,重启多少次都不会改变结果。

无论哪个版本,你最可能遇到的拒绝:

日志说含义
某个数据驱动无法连接OS_DATABASE_URL 中的数据库 —— 或者应用把对象绑定到的某个数据源 —— 无法访问,或者其凭据错误。启动会被拒绝,而不是提供一个对每个请求都报错的服务器。
有一项待处理的破坏性模式变更,并点名了每一项变更新的应用或版本需要一项会丢失数据的变更。先备份,然后用 os migrate apply --allow-destructive 有意识地应用它,再重启。
产物的期望摘要和实际摘要OS_ARTIFACT_URL 上的完整性固定值与获取到的字节不匹配 —— 参见下文。
端口已被占用os start 从不换用其他端口。释放它,或者同时修改 OS_PORT 和代理的上游。
声明了多节点拓扑在一个没有多节点许可证、或协调是进程内的运行时上,OS_CLUSTER_REPLICAS 大于 1。运行一个副本 —— 参见 Docker → 多节点。
Cannot find module 'pg'裸装的 Node.js 没有 PostgreSQL 驱动。镜像中带有 pg 和 mysql2;在镜像之外,把驱动安装在 CLI 旁边(npm install -g pg)。

如果日志中没有致命错误,就检查常见原因:出故障的服务的容器日志,以及探针 —— /api/v1/health 在进程提供 HTTP 服务后即有响应,/api/v1/ready 则要等数据库有 响应之后。

应用不是你预期的那个

部署所提供的应用恰好只来自一个地方,而是哪个地方是由部署声明的决策 —— 参见 启动模式。当运行中的应用不是你发布的那个时:

  • **确认这个部署处于哪种模式。**如果没有设置产物引用,运行时提供的就是它的镜像 所带的内容 —— 在 Community 上,是 /srv/app/objectstack.json 处的文件,或者一个 空内核加上安装进它的应用;在 Enterprise 上,是镜像中编写的元数据,加上安装进它 的任何内容。发布一个新的产物在部署指定它之前不会改变任何东西。
  • 检查启动横幅,它会点名实际加载的应用。
  • 不匹配的完整性固定值会拒绝启动,并同时打印期望的摘要和实际的摘要。同时打印 这两者正是关键所在:它能区分一个被重新发布的产物和一个被替换的产物。
  • **没有固定值、且产物主机不可达时,启动会明确地失败。**在没有固定值的路径上没有 缓存回落 —— 没有任何东西能验证缓存副本的真实性。编排会重试;运行时永远不会自己 捏造一个不同的应用。
  • 有固定值、且主机不可达时,本地缓存的副本可能会被使用 —— 但只限于其字节的 哈希仍与固定值相符的副本,并会以一条警告说明这一点。缓存在每次读取时都会重新 计算哈希;文件名从来不是依据。
  • **设置一个已退役的产物变量并不会选中应用。**在企业版镜像上,其中一个会直接拒绝 启动;其他的则根本没有任何东西读取,所以部署会像你什么都没设置一样启动。 已退役的名称列出了它们 及其替代项。

没有人能登录

在全新的部署上,第一个注册的账户会成为管理员。这条规则计算的是人员,而不是 登录:一个预置了人员记录、却没有登录账户的应用会让数据库看起来已有数据,所以 注册保持关闭,而预置的人员又没有可用于登录的密码。启动日志会以 error 级别在 no_sign_in_account_at_boot 下报告这一情况。恢复要在带外进行 —— 往数据库写入一条 邀请记录,然后进行一次普通的注册;ObjectStack 的 自托管指南 逐步介绍了这一过程。要预防这种情况,就随人员一起预置登录账户,或者在第一个 管理员存在之前让目录保持为空。

登录失败

检查:

  • 已配置 OS_AUTH_SECRET —— 没有它,登录端点会被完全跳过;
  • OS_AUTH_URL 和 OS_TRUSTED_ORIGINS 指定的是公网地址;
  • OIDC 回调 URL 与公网地址一致;
  • ObjectOS 能访问 OIDC 发现 URL;
  • 受信任的源包含公网域名;
  • Cookie 的作用域是部署的公网主机名。

用户看不到记录

检查:

  1. 部署主机名是否正确。
  2. 用户是否属于预期的组织。
  3. 对象的 read 权限。
  4. 行级安全。
  5. 共享规则或记录共享。
  6. 如果只是部分字段缺失,检查字段安全。

设置无法编辑

某项设置可能被环境覆盖值锁定了。生效的设置按以下顺序解析:

Environment -> Tenant -> User -> Default

如果环境提供了值,运行时的编辑应当被拒绝,而不是悄悄地覆盖它。

无法读取存储的密钥

加密的设置、secret 字段和数据源凭据都用 OS_SECRET_KEY 加密。如果它们在一次 重启或恢复之后无法解密,说明密钥变了:一个从未设置它的容器自行生成了一个密钥, 并随文件系统一起丢失了,或者数据库在没有原始密钥的情况下被恢复了。设置托管备份的 原始值 —— 参见备份。新的密钥无法恢复用旧密钥加密的值。

Webhook 或作业不运行

检查:

  • 产物的 requires 列表包含所需的能力;
  • ObjectOS 镜像包含可选的服务包;
  • 队列/作业服务的配置可用;
  • 定时流程和 cron 作业需要 OS_AUTOMATION_SCHEDULED_WORK_ENABLED=true —— 未设置 即为关闭;
  • 允许访问目标的出站网络;
  • 投递日志或作业运行记录在 Setup 诊断中可见。

数据库错误

检查:

  • 数据库 URL 和驱动类型;
  • 从 ObjectOS 到数据库的网络访问;
  • 凭据和 TLS 选项;
  • 模式同步/迁移日志;
  • 如果使用本地 SQLite,检查存储持久化。

企业版额外提供

需许可证的镜像在启动时还会拒绝另外几种配置:

日志说含义
两项设置被一起点名为不受支持的组合一种无法协同工作的许可证模式和云端姿态 —— 最常见的是在一个配置为没有控制平面的部署上使用普通的、在线校验的许可证。物理隔离给出了受支持的矩阵。
隔离墙式部署需要许可证在没有许可证的情况下要求了多组织租户姿态。隔离是一项需许可证的能力;运行时不会假装拥有它来提供服务。
某项决策没有做出在多组织姿态下,新注册用户的成员资格策略和挂载的 AI Agent 集合都没有安全的默认值。声明任何一个可用的值都会被接受;不设置则不行。
设置了一个已退役的变量旧的产物选择变量会拒绝启动,并点名它的替代项。参见已退役的名称。
缺少集群密钥开启集群驱动会使一个在所有副本间共享的加密密钥成为必需。