Repository navigation
Staging CD
当前 updater 清理交付见 PR #15,公开版本为 fc6adc75c7cdb9064163f938a31f176add843e0a。源码、Updater 镜像发布、fc 的 Updater 校验与旧 CD 入口已移除。保留证书 certificate-agent,它只负责 TLS 生命周期,不承担项目升级。
当前发布只编译、发布 Web/Nginx 两种镜像;证书 agent 使用 Web 镜像中的证书命令。升级由每台主机显式执行 fc upgrade plan/apply/open,无自动整群发布、后台 Docker socket 升级或现场源码编译。数据库代际为 7,本次没有 DDL 变化。
现行命令、备份和恢复边界见 fc 手动升级与边界,源码契约以 main 的 运维手册 和 升级契约 为准。RN 预生产和外部 CD 已退役,不能声称完成 live staging 验收。
本次生产执行状态见 fc 手动升级与边界;公开发布成功不等于生产更新完成。
2026-10-11 及此前的历史记录(旧命令及版本不用于当前部署)
当前状态:2026-10-11 所有者已撤销 RN 预发布与 CD,专用容器、卷、接收器和 Runner 已清理;生产存储及其他应用保留。STAGING_CD_ENABLED=false。以下旧预发布步骤仅为历史记录,不能用于现行部署。自动 TLS 改造见 Deployment-and-Configuration,已发布 main/latest(785af2d2c459);这不恢复预发布与 CD。
预发布位于 RN(23.238.8.233,SSH 8964)https://www4399.sbs,使用 frontiercloud-staging 项目。数据、身份、密钥、Redis 和升级器控制卷与同机生产存储完全隔离;生产存储保留 https://www4399.sbs:8443。新预发布由空业务数据初始化,旧 EVOXT 的 Admin Key、媒体预主密钥和业务数据不迁移。查看现有密钥见 部署与配置。
正常链路为 dev 精确源码 CI 成功 → default-main 可信发布器验证并公开三个不可变镜像 → main-only staging-cd-main 签名通知 → RN 9443 接收器持久化去重 → systemd path 唤醒 → 原生 updater 拉取、交接及恢复。通知 202 只代表入队;完成须核对持久化 journal、三个运行组件的完整 SHA 与 /health/ready。无轮询 timer;RN 专用证书 hook 不重启生产存储。
RN 迁移现场已验证最终开发源码 ec58992 的 13 项浏览器检查、账号加密录音快照、独立五条 SQL 下载审计及一核 Web 连续五个低于 20% 的采样。Direct/Relay 证明来自已保留的 DEV 五节点矩阵,RN 现场只测 MasterLocal。历史 schema3 首次迁移及真实 1800 秒上传到期证明单列保留。
PR #6 经维护者明确授权、最终精确源码检查及 RN 现场验收后合并为 8b5cfb9d690db7f160494f449f4adb633924e1e0。合并树与已验收 ec58992 完全一致。main CI 与三个公开镜像发布 成功后,dev 快进至该提交。
dev CI #46 成功,正常可信发布与签名通知 复用已公开的精确镜像并成功通知 RN。接收器 receipt 绑定该 dev run、完整 SHA 与 attempt1。原生 updater 44 秒完成,journal state=success、phase=complete,current/target/updater runtime SHA 全部一致,维护解除;三个实际镜像均为上述 SHA/schema3,HTTPS readiness 和音乐页通过。五个共机非预发布容器 ID、镜像和运行状态保持,一核 Web 限额经过交接保留。
Docker 容器自身的 Config.Labels 可能继承旧容器的版本元数据;核对实际运行版本应读取持久化 updater journal 与容器 .Image 指向的镜像标签,不能只看容器的 revision 标签:
python3 -c 'import json; s=json.load(open("/var/lib/docker/volumes/frontiercloud-staging_updater_control/_data/status.json")); print({k:s[k] for k in ("state","phase","current_sha","target_sha","updater_runtime_sha")})'
for component in web updater nginx; do
image=$(docker inspect --format '{{.Image}}' "frontiercloud-staging-$component-1")
docker image inspect --format '{{index .Config.Labels "frontiercloud.revision"}}' "$image"
doneRN 保留现有 /var/www/certbot 验证目录,www4399.sbs 的模拟续期通过。原有 cargo.8nine64.icu 的 standalone 续期会与预发布 80 端口冲突,已通过独立 ACME-only 虚拟主机和 Certbot reconfigure 验证切为同一 webroot;该域名只有 challenge 路径可读,其他 HTTP 路径为 404。额外只读模板由 /opt/frontiercloud-staging/compose.cargo-acme.yaml 绑定,原生 updater 保留该 bind。手工重建 Nginx 时须加上该 override;只执行 exec 查看密钥不涉及重建。
docker compose --env-file /opt/frontiercloud-staging/.env -p frontiercloud-staging \
-f /opt/frontiercloud-staging/repo/docker-compose.yaml \
-f /opt/frontiercloud-staging/compose.cargo-acme.yaml config -qEVOXT 的旧预发布七个容器、五个卷、网络、业务目录、身份及媒体密钥、接收器/签名密钥、四个 CD unit、专用系统账号、18 项任务文件和 15 个预发布专用镜像已删除。共用证书已迁到 /opt/frontiercloud-shared-tls,生产存储和 Cloudreve 的独立证书续期/HTTP 验证入口保留;生产存储与 Cloudreve 应用容器保持原 ID/镜像,只有两个 HTTPS 代理为更换证书 bind 重建。EVOXT 可用磁盘由约 3.3 GiB 增至 4.6 GiB。未登录或升级生产主节点;生产升级仍由维护者手动执行。
2026-10-08 本次生产迁移由维护者明确豁免预发布验收:开发机验证通过、
dev → main PR 审查合并后直接切换生产。EVOXT 仅准备配置,不启动服务
或 CD;这不代表当时预发布验收通过。
2026-10-09,维护者重新授权启动预发布:EVOXT 独立主节点已启动,公网 HTTPS 就绪检查通过。生产存储实例在同机的 8443 端口,身份、数据和密钥 完全隔离。旧的五分钟 CD timer 已停用,且已从源码移除。
新的 CD 由 dev 的 docker.yml push CI 成功完成事件触发,失败、取消、
main、PR 和外仓库不触发。独立的 workflow_run 工作流只发送签名唤醒,
不检出触发提交、不持有 SSH/root/Docker 权限,不在 GitHub 编译部署。
部署端仍独立核验最新确切 dev SHA 和对应最新成功 CI;不是收到通知就
执行通知里的代码,也不是生产发布授权。
接收端为独立低权限 Go 服务(9443、64 MiB 上限、10% CPU 配额),通过
HMAC-SHA256 校验通知,拒绝过期事件并持久化去重。systemd path 消费
持久化事件后唤醒部署器,没有周期轮询或定时后备任务。GitHub Secret
STAGING_CD_SECRET 已配置;真实 GitHub 通知
成功唤醒了原生升级器。通知返回 202 只代表事件已持久化,不代表部署完成。
构建期间到达的新 CI 事件等待此前的本地升级完成,最长 55 分钟,覆盖 45 分钟构建和八分钟恢复窗口。等待读取专用、标签已核验的升级器控制卷 日志,不依赖交接期间被替换的 web/updater 容器,也不轮询 GitHub。 PR #3 已通过测试并合并; 实际构建期间收到的后续成功 CI 已进入此等待链路。
北京时间 2026-10-09 09:40 完成真实链路验收:
- dev CI #14 成功,工作流总耗时约十秒,没有重型编译或五节点验证。
- 对应 CD 通知 成功;EVOXT 接收日志记录了该 CI 和精确 SHA。
- 首次冷构建更新到
4e32861后,等待中的通知正常消费并部署最新7051c3da71b7d1d1a13a4f0dcbb136f617e71dfd。同目标重复唤醒返回changed=false,未重复构建。 - 持久化升级日志为
state=success、phase=complete,业务版本和升级器运行版本均为上述完整 SHA;本次后续缓存构建、替换和自交接共 84 秒。 - HTTPS
/health/ready返回 200,数据库及 Redis 就绪;音乐页返回 200。升级期间的维护 503 不计为验收通过。 - CD oneshot 已正常退出、结果成功,旧 timer 禁用。生产主节点和两个存储节点仍为
8a6e309,没有被预发布升级器替换。
以上验证的是事件触发、排队、固定版本部署与服务恢复,不等同于每个业务功能的全量回归,也不是生产升级授权。签名密钥的本地传递副本已删除,密钥值不记录在 Wiki 或应用源码。
同日公开网站安全最终候选 e033c3ad8f57392cc5e2f41900e7d2abd891d151
按“开发机全门禁 → 精确 dev CI #17 → 事件 CD → 原生日志与公网完整验收”
顺序通过,PR #4 已合并为 6adfec485488bdcd8393e856f86896c25929aa1b,
main/dev CI #18/#19 均成功,20:33:44(北京时间)预发布交接至合并提交。
此前候选的卡拉 OK 重复头由预发布终验拦下,修复后重跑,未将失败候选
晋升 main。详情见 公开网站安全基线。
20:51(北京时间)为切换镜像交付,旧 Trigger preproduction CD 工作流已
手动停用;源码测试 CI 保持启用和三分钟上限。独立编译/公开镜像及其
完成后 CD 的新流程当时仍在开发机验证。
22:39:15,新 Publish native runtime images 工作流在精确 dev 源码 CI #20
及三个匿名可拉取镜像验证成功后签名唤醒 CD。22:58:44,旧升级器首次桥接
至 05617629dc8f1bbb6cf029d24724d6f6b142d3b0 完成,三个运行镜像及
升级器 journal 版本一致、维护解除。公网 HTTPS/CSP/相对 Admin 重定向/
robots/sitemap/HTTP2/readiness 终验通过,同机生产存储和 Cloudreve 未变。
首次桥接是旧 agent 的限额本地构建,不是新 agent 公开镜像直拉路径的
实际证明;下一次升级需继续验证该路径。新流程无五分钟轮询,旧 runner
不再被使用;具体工作流链接见 公开镜像交付。
控制器复用原生升级器的维护、固定提交构建、持久化日志、自交接与故障 恢复。构建限一个 CPU、1 GiB 内存且不额外使用 swap;失败不会自动解除 维护屏障。CD 托管的预发布站点禁用手动生产升级入口,避免竞争。
生产仍只接受同仓库审核后的 dev → main 发布。
详见 源码内的操作契约。