feat(deploy): 在线更新 - 新增后台检查、强制备份迁移与失败自动回退
This commit is contained in:
@@ -5,7 +5,15 @@ description: 影策后端核心持久化表与状态边界
|
||||
|
||||
# 后端数据库
|
||||
|
||||
后端通过 GORM 管理 SQLite 与 PostgreSQL 表结构。服务启动时由 `backend/internal/database/schema.go` 执行迁移;业务写路径必须通过 service 和 repository 的状态约束,不能直接依赖前端状态。
|
||||
后端通过 GORM 管理 SQLite 与 PostgreSQL 表结构。结构变化由 `migrate-schema` 按版本顺序执行并写入 `schema_migrations`;受管生产部署在 Backend 启动前运行独立迁移服务,Backend 只校验当前 Schema 是否与二进制兼容。业务写路径必须通过 service 和 repository 的状态约束,不能直接依赖前端状态。
|
||||
|
||||
## 结构迁移与版本
|
||||
|
||||
| 表 | 用途 | 关键边界 |
|
||||
| --- | --- | --- |
|
||||
| `schema_migrations` | 保存已成功应用的结构版本、名称、校验和与时间 | 已应用版本的校验和发生变化时拒绝启动;数据库版本高于当前二进制支持版本时拒绝旧程序连接 |
|
||||
|
||||
容器内命令 `migrate-schema up` 应用缺失迁移,`migrate-schema status` 输出当前和期望版本,`migrate-schema verify` 只检查兼容性。`CANVAS_AUTO_MIGRATE=true` 仅用于开发和旧部署兼容;受管生产部署设置为 `false`,并由 Compose 的一次性 `migrate` 服务先完成迁移。后续迁移必须新增版本,不得修改已经发布迁移的实现或校验和。
|
||||
|
||||
## 技能包与版本
|
||||
|
||||
|
||||
13
docs/content/docs/backend/meta.json
Normal file
13
docs/content/docs/backend/meta.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"title": "开发文档",
|
||||
"root": true,
|
||||
"defaultOpen": true,
|
||||
"pages": [
|
||||
"local-development",
|
||||
"code-map",
|
||||
"backend-database",
|
||||
"system-update",
|
||||
"protocol-plugins",
|
||||
"canvas-data-structure"
|
||||
]
|
||||
}
|
||||
60
docs/content/docs/backend/system-update.mdx
Normal file
60
docs/content/docs/backend/system-update.mdx
Normal file
@@ -0,0 +1,60 @@
|
||||
---
|
||||
title: 在线更新与安全回退
|
||||
description: Host Updater、Release 检查、数据库备份迁移、健康验证与异常回退机制。
|
||||
---
|
||||
|
||||
# 在线更新与安全回退
|
||||
|
||||
管理后台的“系统配置 → 系统更新”只负责管理员鉴权、展示状态和发起操作。真正的 Docker、数据库备份与服务切换由宿主机上的 `open-ai-canvas-host-updater` 执行,业务后端不挂载 Docker Socket。
|
||||
|
||||
```text
|
||||
管理员浏览器 → Backend 管理 API → 带 Token 的 Unix Socket → Host Updater → Docker Compose
|
||||
```
|
||||
|
||||
## 安全更新顺序
|
||||
|
||||
1. 从 GitHub Releases 读取包含预览版在内的最高语义版本,并与 `.env` 中固定的 `CANVAS_IMAGE_TAG` 比较。
|
||||
2. 下载目标版本的 `docker-compose.deploy.yml`,执行 `docker compose config --quiet`,检查部署文件、磁盘空间和当前版本。
|
||||
3. 创建 `backup-YYYYMMDD-HHMMSS.zip.partial`,其中包含 PostgreSQL custom-format dump、后端数据目录 tar 和元数据;写入完成后 `fsync`、原子改名,并复核 ZIP 结构和 SHA-256。
|
||||
4. 拉取目标 backend/web 镜像并要求存在仓库 `sha256` 摘要。任何失败都在停服前中止。
|
||||
5. 停止 web/backend,等待 Backend 的 SIGTERM drain 完成;PostgreSQL 和 Redis 保持运行。
|
||||
6. 用目标 backend 镜像独立执行 `migrate-schema up`。整批迁移在事务和 PostgreSQL advisory lock 内完成,迁移名称与 checksum 必须匹配。
|
||||
7. 原子更新 `CANVAS_IMAGE_TAG` 和 Compose 文件,启动目标版本。
|
||||
8. 连续检查 `/api/health/ready` 的数据库、运行时、schema 和 build version,并经过稳定窗口后才标记成功。
|
||||
|
||||
更新状态写入 `/var/lib/open-ai-canvas-updater/state.json`。Backend 或浏览器在切换期间断线不会终止宿主机操作,恢复后可继续读取日志。
|
||||
|
||||
## 自动回退
|
||||
|
||||
停服后的迁移、启动或健康验证失败会触发自动回退:
|
||||
|
||||
1. 停止目标 web/backend;
|
||||
2. 恢复更新前保存的 Compose 文件;
|
||||
3. 再次校验备份 ZIP 和 SHA-256;
|
||||
4. 使用 `pg_restore --clean --if-exists` 恢复 PostgreSQL;
|
||||
5. 恢复旧 `CANVAS_IMAGE_TAG`,启动旧服务并重新进行稳定窗口验证。
|
||||
|
||||
回退任一步失败时状态变为 `manual_intervention`,不伪造成功。管理后台仅在存在旧版本和已校验备份时开放人工回退按钮。
|
||||
|
||||
## 安装与升级约束
|
||||
|
||||
GHCR 镜像部署必须把 `CANVAS_IMAGE_TAG` 固定到具体 Release,不可使用 `latest`。安装更新器:
|
||||
|
||||
```bash
|
||||
cd /opt/open-ai-canvas
|
||||
curl -fsSL https://raw.githubusercontent.com/ddcat-ai/open-ai-canvas/main/scripts/install-host-updater.sh | sudo bash
|
||||
sudo docker compose --env-file .env -f docker-compose.deploy.yml up -d --force-recreate backend web --wait
|
||||
```
|
||||
|
||||
脚本会下载与当前 Release 匹配的 Linux amd64/arm64 二进制和 `SHA256SUMS`,生成随机 `CANVAS_UPDATER_TOKEN`,创建 systemd 服务、Socket 目录、状态目录和 `backups/`。Token 只保存在服务器 `.env` 与 root-only 更新器环境文件中。
|
||||
|
||||
## 运维检查
|
||||
|
||||
```bash
|
||||
sudo systemctl status open-ai-canvas-updater
|
||||
sudo journalctl -u open-ai-canvas-updater -n 200 --no-pager
|
||||
sudo ls -lh /opt/open-ai-canvas/backups
|
||||
sudo sha256sum /opt/open-ai-canvas/backups/*.zip
|
||||
```
|
||||
|
||||
备份文件包含业务数据,应限制为 root 访问并纳入异机备份策略。数据卷本身不是备份。
|
||||
@@ -5,6 +5,15 @@ description: 影策已实现功能的手工验证清单与未确认边界
|
||||
|
||||
# 待测试
|
||||
|
||||
## 服务升级运行基础
|
||||
|
||||
- 完整架构、状态机、Release 清单、备份和回退边界见 `docs/design/dynamic-update.md`。
|
||||
- [x] 后端新增权威 BuildInfo、`schema_migrations`、独立 `migrate-schema` 命令、分层健康检查以及可停止 Worker;专项 Go 测试通过。
|
||||
- [x] 生产 Compose 在 Backend 前运行一次性迁移服务,并使用 `CANVAS_AUTO_MIGRATE=false` 阻止业务进程隐式修改 Schema;Backend 收到 SIGTERM 后进入 drain、停止领取任务并等待活动任务。
|
||||
- [ ] 使用 PostgreSQL 部署执行一次无迁移启动和一次跨版本迁移,确认 migrate 成功后 Backend 才启动,checksum 漂移和高版本 Schema 均会阻止旧 Backend 就绪。
|
||||
- [ ] 在存在图片、视频和文本长任务时发送 SIGTERM,确认 readiness 立即返回 503、新任务被拒绝、已领取任务在宽限期内完成,超时后租约可由重启实例恢复。
|
||||
- [ ] 构建带版本参数的前后端镜像,确认 `/api/system/version`、管理后台版本、OCI Commit 和 Release Tag 一致。
|
||||
|
||||
## 素材库网格密度
|
||||
|
||||
- [x] 素材库桌面端缩小卡片并改为每行 6 张;新增素材占首格,默认每页 35 项,可切换 70/105 项,首屏正好组成 6×6 完整网格;中窄屏按 4/3/1 列收敛,前端生产构建通过。
|
||||
@@ -501,6 +510,19 @@ description: 影策已实现功能的手工验证清单与未确认边界
|
||||
- [ ] 确认浅色/深色主题下标题、分类选中态、搜索焦点环、键帽和滚动区域清晰可见。
|
||||
- [ ] 在窄窗口确认分类可横向滚动、快捷键列表改为单列,弹窗不超出视口且长内容仅在列表区滚动。
|
||||
|
||||
## 管理后台在线更新
|
||||
|
||||
管理后台已新增“系统配置 → 系统更新”,并通过宿主机 Host Updater 执行强制备份、迁移、切换、健康验证和失败回退;以下场景需要在真实 Linux Docker Compose 服务器完成最终确认:
|
||||
|
||||
- [x] 后端 Host Updater、Unix Socket 客户端、管理员 API、版本比较和状态持久化相关测试通过。
|
||||
- [x] 前端 TypeScript 检查、生产构建、侧栏入口、更新器未安装空态、更新器连接态、GitHub Release 日志、浅色/深色主题浏览器验收通过。
|
||||
- [x] Compose 配置校验、systemd 安装脚本语法和 Release 二进制构建命令通过。
|
||||
- [ ] 在生产更新前生成 PostgreSQL + 数据目录 ZIP,确认 `.partial` 不会被当作有效备份,最终 ZIP 可打开且 SHA-256、元数据、`database.dump`、`backend-data.tar` 均有效。
|
||||
- [ ] 从首个在线更新版本升级到包含 schema v2 的测试版本,确认旧服务先 drain,迁移服务独占执行,目标 build version 和 schema version 在稳定窗口内一致。
|
||||
- [ ] 人为让目标版本健康检查失败,确认自动恢复旧 Compose、旧镜像和数据库备份;旧版本因 schema 过高拒绝启动时,必须在数据库恢复完成后才能重新健康。
|
||||
- [ ] 在拉取镜像、创建备份、迁移、启动和健康检查阶段分别模拟失败,确认停服前失败不会改变运行版本,停服后失败进入回退,回退失败明确显示“需人工介入”。
|
||||
- [ ] 更新期间刷新页面、关闭浏览器和 Backend 短暂不可用,确认宿主机操作不中断,恢复后日志与最终状态完整。
|
||||
|
||||
## 管理后台存储资源
|
||||
|
||||
管理后台已新增资源列表、筛选、去重容量统计、预览下载和安全批量删除;以下场景仍需使用真实资源数据确认:
|
||||
|
||||
Reference in New Issue
Block a user