Open Notebook 数据库配置指南:基于 SurrealDB 的环境变量、部署拓扑与多实例隔离
【免费下载链接】open-notebookAn Open Source implementation of Notebook LM with more flexibility and features项目地址: https://gitcode.com/GitHub_Trending/op/open-notebook
Open Notebook 使用 SurrealDB 作为其唯一的主数据存储,承载笔记、来源、笔记本、凭证等全部业务数据。本文基于 docs/5-CONFIGURATION/database.md 展开,完整覆盖五个SURREAL_*核心变量的语义与默认值、三种主流部署拓扑下的连接串写法、端口暴露的安全边界,以及如何用"同一实例多 Namespace/Database"支持多个独立部署,并延伸到仓库源码层的连接建立与自动迁移机制。
SurrealDB 在 Open Notebook 中的角色
从源码结构看,SurrealDB 是 Open Notebook 的持久化基座,而非可选组件:
- 全部数据访问都收敛在 open_notebook/database/repository.py 这一层,对外提供
repo_query、repo_create、repo_upsert、repo_relate等通用封装,业务模块通过它们读写 SurrealDB; - 数据库结构(表、关系、索引)完全由版本化迁移脚本维护,位于 open_notebook/database/migrations 目录下,以
1.surrealql~23.surrealql编号排列,每个迁移都配有一个N_down.surrealql回滚脚本; - 迁移执行器位于 open_notebook/database/async_migrate.py,版本号记录在
_sbl_migrations表中(不存在时视为版本 0,即全新库)。
因此,数据库连接配置是否正确直接决定了 API、Worker 能否启动并完成自动迁移,这是本文将环境变量放在第一优先级讲解的原因。
五个核心环境变量:字段语义与默认值
Open Notebook 通过环境变量定位并认证 SurrealDB,官方文档 docs/5-CONFIGURATION/environment-reference.md 将它们标为"必需"项:
| 变量 | 必需? | 默认值 | 说明 |
|---|---|---|---|
SURREAL_URL | 是 | ws://surrealdb:8000/rpc | SurrealDB WebSocket 连接地址,路径固定为/rpc(RPC 端点) |
SURREAL_USER | 是 | root | SurrealDB 登录用户名 |
SURREAL_PASSWORD | 是 | root | SurrealDB 登录密码 |
SURREAL_NAMESPACE | 是 | open_notebook | 逻辑命名空间(Namespace) |
SURREAL_DATABASE | 是 | open_notebook | Namespace 下的具体数据库(Database)名 |
实际代码与文档互为印证:在 open_notebook/database/repository.py 中,连接 URL、密码、Namespace、数据库名均从环境变量读取,其中密码读取SURREAL_PASSWORD、缺失时回退SURREAL_PASS再回退字面量"root",而 Namespace 与数据库名缺省时统一回退"open_notebook"。
连接建立的真实调用链
repository.py 中的db_connection()是每次访问数据库都会执行的上下文管理器:
async with db_connection() as connection: # connection 已登录并 use 到目标 Namespace/Database其内部顺序为:
- 用
SURREAL_URL构造AsyncSurreal客户端; - 调用
signin(),传入用户名(SURREAL_USER)与密码(见上文回退逻辑); - 调用
use(get_database_namespace(), get_database_name())切到目标逻辑空间; - 业务查询结束后自动
close()。
这解释了为什么五者必须同时正确:仅 URL 正确而SURREAL_USER/SURREAL_PASSWORD与 SurrealDB 启动参数不一致会认证失败;Namespace/Database 与迁移目标不一致则数据会"落错库"。
向后兼容的遗留变量
代码保留了早期命名方式的回退逻辑:未设置SURREAL_URL时,会按SURREAL_ADDRESS(默认localhost)与SURREAL_PORT(默认8000)拼出ws://{address}/rpc:{port}(见 repository.py)。新部署请直接使用规范的SURREAL_URL全量 URL。
三种部署拓扑与推荐配置
官方文档 docs/5-CONFIGURATION/database.md 给出了三个典型场景,区别只在于SURREAL_URL的主机名怎么写——这正是最容易配错的地方。
场景一:SurrealDB 与 Open Notebook 同属一个 docker compose(推荐)
这也是 docs/1-INSTALLATION/docker-compose.md 描述的推荐安装方式。容器之间通过 compose 内部网络通信,主机名直接使用服务名surrealdb:
SURREAL_URL="ws://surrealdb:8000/rpc" SURREAL_USER="root" SURREAL_PASSWORD="root" SURREAL_NAMESPACE="open_notebook" SURREAL_DATABASE="open_notebook"仓库根目录的 docker-compose.yml 即为这一拓扑的标准落地:surrealdb服务以rocksdb:/mydata/mydatabase.db启动、数据卷映射./surreal_data:/mydata,open_notebook服务通过depends_on等待其就绪,两个服务共用同一份SURREAL_USER/SURREAL_PASSWORD(通过${SURREAL_USER:-root}插值,可在.env中一并覆盖,保证两侧始终同步)。
场景二:SurrealDB 跑在宿主机、Open Notebook 跑在 Docker
此时容器内无法使用surrealdb服务名,需要指向宿主机 IP 或 Docker 提供的特殊域名host.docker.internal:
SURREAL_URL="ws://your-machine-ip:8000/rpc" # 或 host.docker.internal SURREAL_USER="root" SURREAL_PASSWORD="root" SURREAL_NAMESPACE="open_notebook" SURREAL_DATABASE="open_notebook"重要安全提示(原文档强调):如果 SurrealDB 容器按文档默认只把端口发布到
127.0.0.1,那么宿主机 IP 上其实是连不通的。若确实需要从宿主机侧访问,请有意识地重新发布端口——参考仓库根目录的 docker-compose.override.yml.example,并且务必放到防火墙或 SSH 隧道之后,同时把SURREAL_USER/SURREAL_PASSWORD换成真实强凭证。
场景三:SurrealDB 与 Open Notebook 跑在同一台机器
适用于两者都直接跑在宿主机本地的场景,或者已弃用的单容器方案(见 docs/1-INSTALLATION/single-container.md,v2 将移除,仓库中仍有示例 examples/docker-compose-single.yml,其内部以ws://localhost:8000/rpc覆盖连接):
SURREAL_URL="ws://localhost:8000/rpc" SURREAL_USER="root" SURREAL_PASSWORD="root" SURREAL_NAMESPACE="open_notebook" SURREAL_DATABASE="open_notebook"三种场景仅替换第一行主机名,其余四行保持一致,这正是 Open Notebook 支持"换库不换逻辑"的设计体现。
端口暴露边界:默认只绑 127.0.0.1 的用意
仓库根目录 docker-compose.yml 对 SurrealDB 端口做了刻意约束:
ports: # Bound to localhost only: the open_notebook service reaches this over # the internal compose network regardless, so the host port is purely # for local debugging (e.g. Surrealist, `surreal sql`). - "127.0.0.1:8000:8000"注释写得很清楚:Open Notebook 容器走 compose 内部网络,根本不需要宿主机把 8000 端口暴露给外部;宿主机的端口仅用于本地调试(如用 Surrealist 可视化工具或surreal sql命令行)。若改成0.0.0.0,任何能触达宿主机的人都可以用默认的root:root以管理员身份连接数据库。
若确实需要跨机器访问(例如在笔记本上用 Surrealist 连开发机),官方提供了 docker-compose.override.yml.example:
services: surrealdb: ports: !override - "8000:8000"注意其中的关键细节:必须使用!override语法替换而非合并 ports(Docker Compose 需 v2.24.4+),否则新旧两条端口规则共存会报 "port is already allocated"。更稳妥的做法是:先通过 SSH 隧道或防火墙限定访问来源,再以真实凭证启动 SurrealDB(把SURREAL_USER/SURREAL_PASSWORD写入.env,两个服务会自动同步读取,见 docker-compose.yml 的注释说明,密码含空格时以 exec 列表形式传参避免被 shell 拆分)。
启动期的自动迁移:为什么"连上库"还不够
正确配置好五个环境变量后,启动流程还有一个与数据库直接相关的环节:自动执行迁移。
在 api/main.py 中,_run_database_migrations()会在 FastAPI 的lifespan里被调用:
- 先执行
_wait_for_database()做只读的就绪探测——ping()会真实发起一次连接并查询_sbl_migrations版本,但对连接失败采用指数退避重试(不重试迁移本身,避免掩盖真正的 schema 错误),从而容忍 compose 环境下 API 比数据库先起的时序问题; - 对比当前版本与内置迁移列表长度(
needs_migration()),有未应用迁移时逐条执行N.surrealql; - 成功后在
_sbl_migrations表写入新版本号;失败则快速失败(fail fast),拒绝用过期 schema 启动 API。
迁移脚本的加载逻辑见 open_notebook/database/async_migrate.py:up_migrations列表按序注册了open_notebook/database/migrations/1.surrealql到23.surrealql,down_migrations对应每个N_down.surrealql,支持单步回滚。对应测试可参考 tests/test_startup_migration_retry.py。
实践意义:如果你"新建"了一套带自定义 Namespace/Database 的库却忘了在其中执行迁移,API 会启动失败或报 schema 缺失——因为迁移只对代码默认与连接目标指向的那套逻辑空间自动执行。这也是为什么文档建议保持默认的open_notebook值或确保每个新库都经过一次正常启动。
写入重试与网络代理两个隐藏配置
除了五个核心变量,数据库行为还受两组环境变量影响,均记录在 docs/5-CONFIGURATION/environment-reference.md:
命令级重试(数据库写入的容错)
| 变量 | 默认值 | 说明 |
|---|---|---|
SURREAL_COMMANDS_RETRY_ENABLED | true | 是否启用失败重试 |
SURREAL_COMMANDS_RETRY_MAX_ATTEMPTS | 3 | 最大重试次数 |
SURREAL_COMMANDS_RETRY_WAIT_STRATEGY | exponential_jitter | 退避策略:exponential_jitter/exponential/fixed/random |
SURREAL_COMMANDS_RETRY_WAIT_MIN | 1 | 单次最小等待(秒) |
SURREAL_COMMANDS_RETRY_WAIT_MAX | 30 | 单次最大等待(秒) |
在多人写入或事务冲突(repository 对可重试冲突仅以 debug 级别记录日志,见 repository.py)的场景下,合理调低MAX_ATTEMPTS、收紧等待区间,可以让失败更早暴露。
NO_PROXY:WebSocket 代理陷阱
Open Notebook 的 SurrealDB SDK 通过 WebSocket 通信,而较新版本的websockets库会把ws://连接也塞进已配置的 HTTP 代理,导致内部数据库主机被代理以 HTTP 403 拒绝,API 与 Worker 双双无法启动。因此NO_PROXY必须显式包含内部主机host.docker.internal(Docker 宿主机场景)与surrealdb(compose 服务名)。
Open Notebook 在 open_notebook/utils/proxy.py 的ensure_internal_no_proxy()中会自动把host.docker.internal,surrealdb,localhost,127.0.0.1合并进no_proxy/NO_PROXY作为安全网,但官方文档仍建议用户自行显式设置,例如:
NO_PROXY=localhost,127.0.0.1,host.docker.internal,surrealdb,.local注意该模块在 repository.py 导入时就执行(API 与 Worker 两条进程路径都会触发),可见这是数据库连通性的前置保障。
多实例共库:一个 SurrealDB 跑多套 Open Notebook
SurrealDB 的逻辑隔离分两层:Namespace(命名空间)之下可以有多个Database(数据库)。Open Notebook 官方文档明确说明:想为不同用户部署多套 Open Notebook,无需部署多个 SurrealDB 实例,只需复用同一实例并用不同的 Namespace/Database 对即可。
结合本文前面的机制,落地方式如下:
- 每套 Open Notebook 部署使用各自唯一的
SURREAL_NAMESPACE与SURREAL_DATABASE(例如SURREAL_NAMESPACE=tenant_a+SURREAL_DATABASE=open_notebook,另一套用tenant_b); - 每套部署首次正常启动时会自动把迁移执行到自己的 Namespace/Database 中,数据彼此物理隔离;
- 所有套共享同一个 SurrealDB 连接端点与认证账号(也可在 SurrealDB 侧按用户权限做更细的账号拆分,但 Open Notebook 侧只需关注这五个变量)。
需要提醒的是:凭证数据在库内经OPEN_NOTEBOOK_ENCRYPTION_KEY加密存储(见 docs/5-CONFIGURATION/environment-reference.md 与 docker-compose.yml),多租户共库时每套部署务必使用不同的加密密钥,避免一处泄漏殃及全部。
常见问题排查速查
结合 docs/1-INSTALLATION/docker-compose.md 与 docs/6-TROUBLESHOOTING/connection-issues.md 的思路,把排查项收敛为三条:
- 启动即失败、日志含认证错误:核对
SURREAL_USER/SURREAL_PASSWORD是否与 surrealdb 容器启动参数(--user/--pass)一致。默认双root,生产必须改; - 迁移报错或表缺失:确认
SURREAL_NAMESPACE/SURREAL_DATABASE与首次初始化时一致,且该 Namespace/Database 确实存在(SurrealDB 通常会在首次use时自动创建,但若你手动建库需保证迁移曾成功执行); - 容器间连不通:Docker 内请用服务名
surrealdb(同 compose)或host.docker.internal(宿主机),不要写localhost;同时确认端口未被防火墙拦截、NO_PROXY已放行内部主机。
全部变量总表与按场景组合的.env示例(Minimal / Production / Corporate 等)可直接查阅 docs/5-CONFIGURATION/environment-reference.md,它与本文共同构成 Open Notebook 数据库配置的完整参考。
【免费下载链接】open-notebookAn Open Source implementation of Notebook LM with more flexibility and features项目地址: https://gitcode.com/GitHub_Trending/op/open-notebook
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考