--- 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` 比较。`sha-*` 这类非正式镜像标签一律视为低于正式 Release,避免把 `vsha-5509b17` 字典序比较成比 `v1.5.0` 更新。 2. 下载目标版本的 `docker-compose.deploy.yml`,执行 `docker compose config --quiet`,检查部署文件、磁盘空间和当前版本。当前标签不是 `vX.Y.Z` 时,健康检查只确认服务就绪,不要求构建号和镜像标签逐字相同。 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 更新器环境文件中。 ## 镜像发布与质量门禁 `main` 推送、`v*` 标签和手动发布统一由 `.github/workflows/publish-images.yml` 编排。发布先调用可复用的 `quality.yml`;PR 仍直接运行质量检查。Go 测试、前端格式、类型、Lint、单测和 Chrome E2E 任一失败,都不能进入镜像构建和发布阶段。若仓库规则配置了必需检查,切换后应核对实际 check 名称,避免仍等待旧的独立 push 工作流。 构建和发布分为以下阶段: 1. 校验 `VERSION`;版本标签必须与文件一致,且存在对应 `CHANGELOG.md` 标题。构建时间取提交时间,同一 SHA 不因重跑而改变。 2. 后端分别在 `ubuntu-24.04`(AMD64)和 `ubuntu-24.04-arm`(ARM64)原生编译,保留 CGO 与三个服务/迁移二进制。支付插件在每个平台的镜像阶段重新打包并执行 smoke;PR 则独立执行双架构 smoke,不依赖发布。 3. 前端 Bun 构建阶段固定到 `BUILDPLATFORM`,静态资源只生成一次,再放入 AMD64/ARM64 nginx 镜像。Bun 与 `web/package.json`、质量检查保持 `1.3.9` 一致。 4. 先推送 `sha-<完整提交>-amd64/arm64` 后端镜像及 `sha-<完整提交>-multi` 前端镜像,以摘要 artifact 传递结果。两种后端架构和前端全部成功后,才从摘要合并发布 manifest,不用可变标签作为合并源。 5. 同一 SHA 的 main/tag 发布串行运行;后到的一轮仍经过质量门禁,然后复用已有 SHA 镜像,不重复编译。只有明确的镜像不存在可以转入构建,鉴权、限流、网络和异常摘要必须报错。 6. 发布保留完整 SHA 和短 SHA 标签;只有版本 tag 推送写入具体版本标签。`main` 只有在仍是远端最新提交时才更新 `latest`,旧提交的慢任务不能覆盖新版本。正式部署仍应固定版本标签,不依赖 `latest`。 Go 检查显式使用 `backend/go.sum` 作为缓存依赖键,并上传 `go-test-timings`(JSONL),可按 `Test` / `Elapsed` 定位慢测试。Docker 的后端模块下载保留在普通镜像层,编译步骤可以直接读取;支付插件只按实际 import 下载依赖,不重复预取完整后端模块图。版本参数下移到编译入口。GHA 构建缓存按镜像和架构隔离,避免并行任务共用同一 scope。`go-build` cache mount 只用于同一个 builder 内的复用,当前没有额外的跨 Runner mount 导出方案;不能把它当作持久编译缓存。冷缓存首轮和缓存上传仍可能较慢,需要比较连续两轮的实际耗时。 这套发布流程依赖仓库可使用 GitHub 原生 ARM64 Runner、GHCR 写权限以及构建/下载 artifact 能力。首次上线应核对实际 Runner 排队情况、双架构 manifest、main/tag 同 SHA 复用和质量失败阻断;本地测试不能代替这些云端验收。工作流变更不迁移业务数据库,也不修改服务器 Compose 或数据卷。需要回退 CI 时只回退工作流和 Dockerfile 改动;已发布镜像不会自动撤回,线上版本回退仍按本文的备份与迁移约束执行。 ## 运维检查 ```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 访问并纳入异机备份策略。数据卷本身不是备份。