This page was machine-translated. Spotted a mistake?Help improve it.
Skip to content

从 1.x 升级到 2.0

SnapOtter 1.x 将所有内容存储在单个 SQLite 文件中,并以单容器方式运行。SnapOtter 2.0 使用 PostgreSQL 和 Redis。本指南将带你把 1.x 安装迁移到 2.0 而不丢失数据。

简要版:复用你现有的 /data 卷,2.0 会在首次启动时自动导入你的 1.x 数据库。你的用户、已保存的文件、设置、API 密钥和流水线都会一并迁移过来。旧数据库从不会被修改,因此你随时可以回滚。

致我们的 1.x 用户

你们中的许多人从第一天起就信任 SnapOtter,你们的反馈塑造了这个版本。2.0 在底层做了大量改动,本指南的存在就是为了让这次迁移不会让你损失任何在意的东西。你的账户、文件、设置、API 密钥和流水线都会平移过来,你的旧数据库从不会被触碰。感谢你与我们一同升级。

开始之前:备份整个 /data

每次都先做这一步。备份整个 /data 卷,而不仅仅是 snapotter.db 文件。

原因如下。1.x 以 WAL 模式运行 SQLite,因此一个已停止的 1.x 容器通常会把大部分已提交的数据留在 snapotter.db-wal 中,旁边只有一个几乎为空的 snapotter.db。仅复制 snapotter.db 会抓到一个空数据库,并悄无声息地丢失所有内容。该卷同时携带 snapotter.dbsnapotter.db-walsnapotter.db-shm 以及你的 files/ 目录,它们必须作为一个整体一起迁移。

bash
# Adjust the volume name to match yours (see "Check your volume name" below).
docker run --rm -v SnapOtter-data:/data -v "$PWD":/backup \
  alpine tar czf /backup/snapotter-1x-data.tgz -C /data .

先升级到 1.17.2

在迁移到 2.0 之前,先把你的 1.x 安装升级到最新的 1.x 版本(1.17.2)。这能让 1.x 运行它自己的最终 schema 迁移,从而让 2.0 从一个已知且完整的 schema 导入。不支持从更旧的 1.x 直接升级到 2.0。

检查你的卷名

只有当 2.0 栈挂载的卷与你的 1.x 安装使用的卷相同时,导入器才能看到你的数据。Docker 卷名区分大小写,较旧的 README 片段用的是小写的 snapotter-data,而 Compose 文件用的是 SnapOtter-data。确认你用的是哪一个:

bash
docker volume ls | grep -i snapotter

在你的 2.0 配置中使用那个确切的名称。

路径 A:单容器(最快)

如果你用单个 docker run 运行 SnapOtter,那就继续这么做。当你不设置 DATABASE_URLREDIS_URL 时,2.0 会在容器内启动一个内嵌的 PostgreSQL 和 Redis,并在首次启动时自动检测并导入 /data/snapotter.db

bash
docker run -d --name snapotter -p 1349:1349 \
  -v SnapOtter-data:/data \
  snapotter/snapotter:latest

留意日志中类似这样的一行:

Imported 1.x SQLite database: {"tables":{"users":2,"teams":1,...},"blobs":{"present":1,"missing":0}}

就这样。用你现有的凭据登录即可。

2.0 Compose 栈运行三个服务(应用、Postgres、Redis)。为应用服务复用你的 1.x /data 卷。应用会自动检测 /data/snapotter.db 并在首次启动时将其导入 Postgres。

yaml
services:
  SnapOtter:
    image: snapotter/snapotter:latest
    volumes:
      - SnapOtter-data:/data          # your existing 1.x volume
      - SnapOtter-workspace:/tmp/workspace
    environment:
      - DATABASE_URL=postgres://snapotter:snapotter@postgres:5432/snapotter
      - REDIS_URL=redis://:snapotter@redis:6379
    # ...

如果你更想显式指向旧数据库,设置 SQLITE_MIGRATE_PATH=/data/snapotter.db。显式路径始终优先于自动检测。

先预览导入(可选)

若想在不写入任何内容的情况下准确查看将会导入什么,可针对你的数据库文件运行一次 dry run:

bash
pnpm --filter @snapotter/api migrate:sqlite -- /path/to/snapotter.db --dry-run

它会打印每个表的行数、在磁盘上找到的已保存库文件数量,以及任何将被规范化的任务状态。它无需运行中的 Postgres。

哪些会迁移,哪些不会

会迁移的:

  • 用户,以及登录能力。密码哈希保持不变,因此相同的用户名和密码仍然有效。
  • 团队、设置(包括你的实例标识)、角色、API 密钥(它们继续有效)以及已保存的流水线。
  • 任务历史记录。
  • 你已保存的文件库,包括记录和实际文件,因为 /data/files 在卷上得到保留。

不会迁移的:

  • 登录会话。升级后每个人都需要重新登录一次。凭据保持不变,因此这只是一次性重新登录,仅此而已。
  • 旧处理任务的输入和输出文件。它们存放在临时工作区中,按设计已被清除。任务历史记录仍然保留。
  • 来自 1.x 的每用户分析同意标记,它在 2.0 中没有对应项(2.0 的分析是实例级设置)。

关闭导入

如果即便卷上存在 snapotter.db,你也刻意想要一个全新的数据库,请设置 SQLITE_MIGRATE_PATH=off

如果 2.0 实例中已有数据

导入器只会在空数据库上运行。如果你全新启动了 2.0(创建了数据),随后又挂载了一个旧的 snapotter.db,2.0 会检测到它但不会导入,因为合并两个数据集可能会在 ID 上冲突。你会在日志中看到一条警告。要导入 1.x 数据,你需要一个空实例:

  • 如果 2.0 实例只包含默认管理员(你其实还没真正使用过它),停止栈,移除 Postgres 卷(SnapOtter-pgdata),然后在旧的 /data 存在的情况下再次启动。它会干净地导入。这只会抹掉一次性的 Postgres 数据,而不是你的 1.x 数据库。
  • 如果 2.0 实例包含你想保留的真实数据,那这两个数据集无法自动合并。请导出你需要的内容,并将 1.x 数据导入到一个独立的全新部署中。

回滚

升级从不会修改或删除你的 1.x snapotter.db。如果你需要回退到 1.x,针对同一个卷重新部署 1.x 镜像即可。升级后你在 2.0 中创建的任何内容都存在于 Postgres 中,不会出现在 1.x 数据库里,所以如果打算回滚,请尽早进行。