Skip to content

升级与备份

升级会更新应用代码,也可能更新数据库表结构。部署旧的镜像 tag 可以恢复应用代码,但无法撤销数据库表结构变更。

自部署总览说明了三个平台在全新安装时执行迁移的时机。升级采用相同的时机,但还需要保护数据库中的现有数据。

每次升级前先备份

请备份 Postgres。 看板、反馈、投票、评论、更新日志条目、账号、登录会话和相似反馈检测使用的向量数据都存储在 Postgres 中。没有数据库备份,就无法恢复这些数据。

bash
pg_dump --format=custom "$DATABASE_URL" > feedlog-$(date +%F).dump

应用运行期间也可以执行此命令,无需停机。备份完成后,先在临时数据库中恢复一次,确认备份可用。

上传的文件需要单独备份。 文件位置取决于存储配置:

存储方式文件在哪升级时的风险
S3 兼容存储(配了 S3_*)、Cloudflare R2、Vercel Blob你自己的存储桶或存储服务部署不会修改这些文件。请单独备份
未配置存储(Docker)容器内的 /app/.data除非该路径挂载了卷,否则删除容器时也会删除这些文件

未设置 S3_* 变量时,上传功能会使用本地文件系统驱动,并将文件写入容器。仓库中的 compose.yml/app/.data 挂载了命名卷(named volume),因此删除容器时会保留这些文件。如果使用单行 docker run 命令部署但没有添加 -v,文件不会保留,而 Docker 升级中的 docker rm 步骤会将它们删除。

请同时备份环境变量,尤其要保留 BETTER_AUTH_SECRET。更改该值会使所有用户的现有登录会话失效,并使待使用的密码重置和邮箱验证链接失效。

升级

bash
docker pull ghcr.io/linkcraftstudio/feedlog:v0.2.0
docker stop feedlog && docker rm feedlog
docker run -d --name feedlog -p 3000:3000 \
  ... same env vars as before ... \
  ghcr.io/linkcraftstudio/feedlog:v0.2.0
docker logs -f feedlog        # wait for "Database migration completed"

# With the bundled compose file: edit the image: tag, then
docker compose pull app && docker compose up -d app
bash
git pull upstream main
git push          # Vercel rebuilds; migrations run in the build step
bash
git pull upstream main
pnpm install
pnpm build:cf && pnpm deploy:cf
# Then visit the site as a signed-in admin; see below

各平台的完整步骤保存在代码仓库中,并与正在部署的版本一起发布: Docker · Vercel · Cloudflare Workers

该部署哪个 tag

Tag指向什么
latestmain 分支的最新构建。发布新构建时会变化
v0.2.0指定的正式发布版本。不会变化
0.2该次要版本中最新的补丁版本。发布新补丁时会变化
sha-1a2b3c4指定的一次提交。不会变化

试用 FeedLog 时可以使用 latest。生产环境应使用 vX.Y.Zsha- 开头的 tag。否则,宿主机因其他原因重启后,再次运行 docker compose up -d 可能会意外部署新版本并执行迁移。因此,仓库自带的 compose.yml 使用固定的版本 tag。

升级时的数据库迁移

迁移时机与全新安装相同,但升级时还需要在迁移失败后处理现有数据。

  • Docker:容器启动时执行待处理的迁移。Postgres advisory lock 会让迁移按顺序执行,因此两个容器同时启动时不会重复执行同一条迁移;第二个容器会等待,并在获得锁后确认没有待处理的迁移。该锁不能防止旧版本应用使用新的表结构,因此升级时应先停止旧版本,再启动新版本,不要逐个替换多个副本。将流量切换到新容器之前,请等待日志中出现 Database migration completed。进程开始运行后 /health 就会返回 200,此时迁移可能尚未完成。
  • Vercel:迁移在 Nuxt 构建之前执行。迁移失败会使本次部署失败,上一个部署继续提供服务,因此失败的表结构变更不会进入生产环境。DATABASE_URL 必须同时设置在 Production 和 Preview 作用域中,而且 Vercel 构建机器必须能够连接你的 Postgres。
  • Cloudflare Workers:Worker 没有启动阶段,迁移只能在收到请求时执行。因此,升级还需要完成下文所述的手动操作。

Cloudflare Workers 升级需要管理员确认

运行 pnpm deploy:cf 后,如果该版本包含尚未执行的迁移,Worker 会将站点切换到 setup 状态:所有页面请求跳转到 /setup,所有 /api/ 请求返回 503NOT_INITIALIZED/setup 页面随后尝试执行迁移。因为这是升级而不是首次安装,该接口要求调用者是已登录的管理员。未登录的访问者会收到 "Administrator required"。此限制用于防止普通访问者触发数据库表结构变更。

在 setup 状态下,除 /setup/api/auth/**/health 和静态资源之外,其他请求都会跳转,其中也包括显示登录弹窗的页面。如果新版本 Worker 上线时没有管理员登录会话,就无法通过界面登录。

部署之前先登录

运行 pnpm deploy:cf 之前,请打开实例并确认当前已以管理员身份登录。部署不会使登录 cookie 失效。部署完成后打开任意页面,Worker 会将请求重定向到 /setup,执行迁移,再返回原页面。如果未登录就进行部署,站点只能提供 /setup,而该页面会返回 "Administrator required"。

如果 /setup 无法继续,请直接请求 /api/_migrate/status。该接口会返回 state、已执行的迁移数量(applied)和预期的迁移数量(expected)。

回滚

回滚应用代码有三种方式:部署上一个镜像 tag;在 Vercel 控制台重新部署上一个版本;或者切换到旧 commit 后再次运行 pnpm deploy:cf

FeedLog 不支持回滚数据库表结构。迁移记录保存在跟踪表中,并且只向前执行;FeedLog 不提供反向迁移。已发布的迁移包含删除索引、删除唯一约束和将字段改为 NOT NULL 等操作。旧版本应用使用此类表结构时,可能出现行为异常或无法启动。

回滚前,请先确认属于以下哪种情况:

  • 新版本有 bug,但没有执行任何迁移。 部署旧 tag 即可,无需恢复数据库。大部分回滚属于这种情况。
  • 新版本执行了迁移。 部署旧 tag,并且恢复升级前的 Postgres 备份。升级后、回滚前写入的数据会丢失,因此应在业务低峰期升级。

Docker 和 Vercel 的部署日志会显示已执行的迁移。Cloudflare 部署完成后可通过 /api/_migrate/status 查询。

要恢复的是数据库,不只是镜像

仅将容器回退到上一个 tag 不会撤销迁移。如果新版本修改过数据库表结构,还必须恢复升级前的数据库备份。

常见报错

容器启动后立即退出,并反复重启。 迁移失败。docker logs feedlog 中的 Database migration failed 行包含具体错误。此时表结构已完成部分变更。请先解决失败原因再重启,或者恢复备份后重新升级。

容器重启后页面返回 500,稍后恢复。 进程开始监听端口时,迁移仍在执行。请等待日志中出现 Database migration completed,再将流量切换到该容器。/health 返回 200 不代表表结构已就绪。

Vercel 部署在迁移步骤失败。 上一个部署仍在提供服务。常见原因是 DATABASE_URL 未在 Production 作用域中启用,或者 Vercel 的构建 IP 无法连接数据库,例如 Postgres 部署在 VPN 后的自有机房中。

/setup 显示 "Administrator required",但无法登录。 部署前没有建立管理员登录会话。请使用仍保留有效管理员会话的浏览器,再刷新 /setup

Docker 升级之后上传的图片返回 404。 该实例使用本地文件系统存储,但 /app/.data 没有挂载卷,因此 docker rm 同时删除了文件。这些文件无法恢复。下次升级前请先配置 S3_* 存储。参见配置外部服务

升级后所有用户都退出了登录。 BETTER_AUTH_SECRET 已更改,通常是因为新部署生成了新值,而不是沿用原值。恢复原值后,原有会话会恢复。

开源的反馈收集工具。可以自己部署,也可以用我们托管的版本。