本文适用于已经在 1Panel 中完成部署、准备为 Mix Space Core 与 Yohaku 增加自动更新能力的环境。本文不会改变现有部署架构,也不包含首次安装步骤。文中的
<BLOG_DOMAIN>、<APPROVED_VERSION>、<RELEASE_ID>等均为占位符,执行前必须替换为实际值。
先读结论
这套方案将两个组件分开更新,并固定执行顺序:
- 北京时间
03:00,1Panel 检查并更新 Mix Space Core。 - 北京时间
03:30,GitHub Actions 检查 Yohaku 上游版本;仅在版本变化时构建并发布。 - Core 更新前强制备份 PostgreSQL;Yohaku 发布失败时自动切回上一版本。
- 每次实际更新后都必须检查本机服务、公开路由、Webhook 与 WebSocket。
| 组件 | 当前管理方式 | 更新触发方式 | 有更新时执行的动作 |
|---|---|---|---|
| Mix Space Core | /opt/mix-space 中的 Docker Compose | 1Panel 每日计划任务 | 拉取官方镜像 → 备份 PostgreSQL → 执行迁移 → 重建 Core → 健康检查 |
| Yohaku | GitHub Actions 构建,发布到 /opt/yohaku/releases | GitHub Actions 每日检查上游 | 构建 release → 切换软链接 → 重启 1Panel Node.js 容器 → 健康检查;失败则回退 |
一、适用范围与安全边界
1.1 本文使用的环境参数
| 项目 | 值 |
|---|---|
| Mix Space 部署目录 | /opt/mix-space |
| Mix Space 官方镜像 | innei/mx-server:<APPROVED_VERSION> |
| Core 本机地址 | http://127.0.0.1:2333 |
| Yohaku 发布根目录 | /opt/yohaku |
| Yohaku 本机地址 | http://127.0.0.1:2323 |
| 站点域名 | https://<BLOG_DOMAIN> |
| Core 更新任务 | 北京时间每天 03:00 |
| Yohaku 检查任务 | 北京时间每天 03:30 |
如果你的实际目录、端口、域名或容器名不同,应先统一替换全文中的对应值,再执行命令。
1.2 必须遵守的边界
- Core 只使用官方镜像,并在生产环境固定到已审阅的版本标签
innei/mx-server:<APPROVED_VERSION>。 - PostgreSQL 和 Redis 不纳入每日自动更新范围。
- Core 更新前必须成功创建数据库备份;备份失败时立即停止。
- Core 数据迁移可能不可逆,因此更新失败时不自动恢复旧数据库。
- Yohaku 始终在 GitHub Actions 中构建,服务器不拉取或编译 Yohaku 源码。
- Yohaku 继续由 1Panel Node.js Runtime 管理,不引入 PM2,也不改造成 Compose 应用。
- 密码、PAT、Webhook Secret、SSH 私钥等凭据不得写入脚本、工作流、日志或部署记录。
- 第一次启用自动更新前,必须先手动执行一次并完成全量验收。
不建议对生产环境的 innei/mx-server:latest 开启无人值守更新。主版本升级可能包含不可逆数据库迁移。推荐做法是:先阅读发布说明、在测试环境验证,再同时更新 Compose 和本节脚本中的 <APPROVED_VERSION>,最后由计划任务完成已批准版本的发布。
[!IMPORTANT] 本文中的脚本会拉取镜像、备份数据库、重建容器、重启 Yohaku,并清理过期备份或旧 release。首次执行时请全程观察日志,不要直接启用无人值守任务。
二、启用自动化前的基线检查
自动化只负责更新,不能替代故障排查。先确认当前站点正常,才能区分“更新前已有问题”和“更新导致的问题”。
2.1 检查 Core 的 Compose 配置
cd /opt/mix-space
docker compose config --quiet
docker compose config --services
docker compose ps
至少应看到以下服务:
appmx-migratepostgresredis
mx-migrate 是一次性迁移服务。执行成功后显示 Exited (0) 属于正常状态,不需要让它常驻运行。
2.2 记录实际容器名
本文的 Core 脚本优先使用 Compose 服务名,避免绑定 PostgreSQL 的具体容器名。Yohaku 发布脚本仍需知道 1Panel 创建的实际容器名:
docker ps -a --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}' \
| grep -E 'mx-|postgres|redis|yohaku'
下文用 yohaku 作为 Yohaku 容器名。如果实际名称不同,请修改发布脚本中的 YOHAKU_CONTAINER。
2.3 检查 Yohaku 软链接
readlink /opt/yohaku/current
readlink /opt/yohaku/server.js
test -f /opt/yohaku/server.js
建议使用相对软链接,典型结果如下:
releases/<release-id>/<standalone-subpath>
current/server.js
这样将宿主机 /opt/yohaku 挂载到容器 /app 后,链接仍然有效。
2.4 保存本机和公网访问基线
Core Ping 应返回:
2.5 单独检查 WebSocket
完整可用的结果应包含:
HTTP/1.1 101 Switching Protocols
收到 101 后 curl 因连接保持而超时是正常现象;判断依据是响应头中的 101 Switching Protocols。
当前 Core v14 以 /ws/web 作为前台 WebSocket 验收路径;后台实时功能可额外检查 /ws/admin。/socket.io 只应作为旧客户端兼容性附加检查,不能作为当前部署的通过条件。启用自动更新前,应先排除既有的 Core 日志、OpenResty /ws/ 转发或 CDN WebSocket 配置问题。
三、配置 Mix Space Core 自动更新
3.1 工作流程
Core 更新脚本按以下顺序执行:
数据库备份和迁移之间不会穿插其他更新步骤。任何一步失败,脚本都会以非零状态退出,让 1Panel 记录失败并发送通知。
3.2 在 1Panel 创建脚本库脚本
进入 计划任务 → 脚本库 → 创建:
- 脚本名称:
自动更新-Mix-Space-Core - 脚本内容:
3.3 为什么这样写
- 使用
flock防止手动执行与定时任务重叠。 - 先比较正在运行的容器镜像 ID 与拉取后的镜像 ID;没有变化时不备份、不迁移、不重启。
- 使用
docker compose exec -T postgres,依赖稳定的服务名,而不是写死mx-postgres或postgres等容器名。 - 使用
pg_dump -Fc生成 PostgreSQL 自定义格式备份,并用test -s确认文件非空。 - 使用带唯一名称的
docker compose run --no-deps --name ... mx-migrate显式执行一次性迁移;成功后删除容器,失败时保留容器及其日志,避免--rm使本次失败原因丢失。 - 脚本将标准输出同时追加到
/opt/mix-space/logs/core-update.log;即使 1Panel 的“报告”页未保留记录,也有独立日志可追溯。应通过logrotate或等效机制轮转该文件,避免长期增长占满磁盘。 - 只有迁移成功后才重建
app;健康检查最多等待 3 分钟。 - 仅在更新成功后清理 14 天前的备份;失败时保留备份和日志。
脚本不会在 Core 更新失败后自动恢复旧数据库。应用镜像回退与数据库恢复必须结合迁移兼容性人工判断,不能仅凭“服务启动失败”就覆盖数据库。
3.4 第一次手动验证
在脚本库中点击 执行。正常结果分为两种:
- 没有新镜像:输出
Core 已是最新镜像,不重启服务,随后 Ping 成功。 - 有新镜像:依次出现备份、迁移、重建与
Core 更新成功。
执行后检查:
如果没有新镜像,脚本不会创建备份,也不会重启 Core,这是预期行为。
3.5 创建每日计划任务
进入 计划任务 → 计划任务 → 创建:
| 字段 | 建议值 |
|---|---|
| 任务名称 | 每天更新-Mix-Space-Core |
| 任务类型 | Shell / 脚本库 |
| 脚本 | 自动更新-Mix-Space-Core |
| 执行周期 | 自定义 Cron |
| Cron | 0 3 * * * |
| 超时时间 | 20 分钟 |
| 失败通知 | 开启 |
| 执行记录保留 | 至少 14 次 |
确认服务器时区:
timedatectl status
应显示 Asia/Shanghai。创建任务后,再从计划任务列表手动执行一次,并确认执行记录的退出码为 0。
还要进入“报告”确认该次执行的完整输出可见;不能只看任务列表的绿色状态。若当前 1Panel 版本未保存报告,至少应确认以下日志存在且包含本次时间:
tail -n 200 /opt/mix-space/logs/core-update.log
四、配置 Yohaku 自动更新
4.1 更新策略
Yohaku 的源码和构建过程留在 GitHub Actions:
- 每天只检查一次上游提交。
- 构建哈希未变化时直接结束,不上传 release,也不重启服务器容器。
- 上游有变化时才构建并发布。
- 新 release 启动失败时,恢复
current的旧目标并重启。 - 只有新 release 健康检查通过后,才清理旧 release。
4.2 先审计部署仓库
本章不是官方 yohaku-deploy-action 的完整替代工作流,而是在已经适配 1Panel 的用户 fork上增加定时检查与回退逻辑。修改前逐项确认当前 .github/workflows/deploy.yml 已满足:
- 已启用
workflow_dispatch,可手动验证。 - 构建 Node.js 版本固定为 22,不能使用浮动的
lts/*。 - 构建命令为
pnpm --filter @yohaku/web build:ci,并产出standalone/apps/web。 - 发布根目录是
/opt/yohaku/releases/<run-number>,不是$HOME/yohaku。 current和server.js使用相对软链接。- 首次 release 安装路径与后续“已有 Runtime 容器”的更新路径已经分开处理。
- 工作流权限遵循最小权限原则,不使用
permissions: write-all。
任一项不满足时,先完成 workflow 改造和手动测试;不要把本章的局部片段直接拼进未经审计的官方工作流。
4.3 配置 GitHub Actions 定时检查
编辑部署仓库 wanxiao-wx/yohaku-deploy-action 中的 .github/workflows/deploy.yml:
on:
push:
branches:
- main
schedule:
- cron: "30 19 * * *"
workflow_dispatch:
repository_dispatch:
types: [trigger-workflow]
GitHub Actions 的计划任务使用 UTC。19:30 UTC 对应北京时间次日 03:30,与 Core 的 03:00 错开 30 分钟。
保留工作流原有的 Check Should Rebuild 判断:
build_hash等于上游当前提交:结束任务,不构建。build_hash不等于上游当前提交:继续构建和发布。
提交触发器修改:
git add .github/workflows/deploy.yml
git commit -m "ci: schedule daily Yohaku update checks"
git push
随后使用 workflow_dispatch 手动运行一次。上游没有变化时,在 Check Should Rebuild 后正常停止属于“无需更新”,不是失败。
4.4 为远程发布脚本增加健康检查与回退
先确认 Yohaku 的实际容器名:
docker ps -a --format '{{.Names}}' | grep -i yohaku
在现有远程发布脚本中,完成新 release 解压、.env 链接和 .next/cache 链接之后,再执行以下切换逻辑:
这段逻辑比单纯“重启后访问一次”多做了三项保护:
- 切换前确认旧
current存在,保证具备回退目标。 - 新版本失败后不仅恢复软链接,还会再次检查旧版本是否真正恢复。
- 使用以 NUL 分隔的目录列表清理 release,避免目录名中存在空格时被错误拆分。
basedir、RUN_NUMBER 和 STANDALONE_SUBPATH 应由现有发布脚本在前文正确赋值。本节只替换“切换软链接、重启、验收、清理”部分,不是完整的独立发布脚本。
4.5 确认 1Panel Node.js Runtime 导出环境变量
不同 1Panel 版本的容器挂载点并不相同,不能直接假定 .env 一定在容器内的 /app/.env。先检查实际挂载与已导出的变量:
确认容器内的项目挂载点为 <CONTAINER_APP_DIR> 后,再检查 /opt/1panel/runtime/node/yohaku/run.sh。例如挂载点确实为 /app 时,应包含:
if test -f /app/.env; then
set -a
. /app/.env
set +a
fi
若实际挂载点不是 /app,应将上述路径替换为已验证的 <CONTAINER_APP_DIR>/.env。仅读取 .env 而没有 set -a 不会自动把普通变量导出给 Next.js 子进程。
同时确认 Yohaku 的 .env 显式设置:
PORT=2323
否则 Next.js 可能回到默认端口 3000,导致 OpenResty 代理到 2323 时返回 502。
4.6 提交并测试发布流程
git add .github/workflows/deploy.yml
git commit -m "ci: verify and roll back Yohaku deployments"
git push
手动触发一次有实际构建的发布。通过标准:
/opt/yohaku/current指向新 release。- Yohaku 容器完成重启。
http://127.0.0.1:2323/返回成功响应。- GitHub Actions 全部成功。
/opt/yohaku/releases保留最近 5 个 release,或在总数不足 5 个时全部保留。
五、每次实际更新后的统一验收
不要仅以“计划任务绿色”或“GitHub Actions 成功”作为最终结果。实际更新后按以下顺序检查。
5.1 本机服务
5.2 公网关键路由
三个地址都应返回 HTTP 200。
5.3 迁移和运行日志
cd /opt/mix-space
docker compose logs --tail=100 app
tail -n 200 /opt/mix-space/logs/core-update.log
docker logs --tail=100 yohaku
关注以下内容:
- 本次更新的迁移日志显示成功完成;成功迁移容器会被脚本删除,失败迁移容器会保留并在日志中标出名称。
- Core 没有持续重启、数据库连接或迁移错误。
- Yohaku 没有持续重启、端口冲突或 API 连接错误。
5.4 Webhook
登录 https://<BLOG_DOMAIN>/qaqdmin,打开 Yohaku Webhook 的投递记录。最新的 health_check 应同时满足:
- HTTP 状态为
200。 success为true。
创建 Webhook 时返回 HTTP 204 可以是正常结果;真正的联通性应以 Core 生成的 health_check 投递记录为准。
5.5 WebSocket
重复第二章的 WebSocket 握手命令。只有响应包含 101 Switching Protocols,才算完整验收通过。
如果普通网页返回 200,但 WebSocket 不是 101,优先检查:
- OpenResty 的
/ws/是否代理到127.0.0.1:2333。 - 是否传递
Upgrade与Connection请求头。 - Cloudflare 或其他 CDN 的 WebSocket 支持是否开启。
- Core 日志中是否出现握手或 Origin 错误。
5.6 记录版本证据
docker inspect --format '{{.Config.Image}} {{.Image}}' \
"$(cd /opt/mix-space && docker compose ps -q app)"
readlink /opt/yohaku/current
在当前站点对应的部署记录中追加,例如 docs/deployments/YYYY-MM-DD-<BLOG_DOMAIN>.md:
- 更新时间。
- Core 镜像摘要。
- Yohaku release 编号。
- GitHub Actions run ID。
- 本机与公网检查结果。
- Webhook 和 WebSocket 结果。
部署记录中不得出现密码、Token、Webhook Secret 或其他凭据。
六、失败时如何处理
| 故障场景 | 自动化行为 | 人工处理重点 |
|---|---|---|
| Core 镜像拉取失败 | 任务失败,旧容器不变 | 检查网络、镜像仓库和磁盘空间 |
| PostgreSQL 备份失败 | 立即停止,不执行迁移 | 检查数据库状态、空间、目录权限;不得绕过备份继续更新 |
mx-migrate 失败 | 不重建 Core,保留备份 | 查看迁移日志,确认版本与数据库状态 |
| Core 重建后健康检查失败 | 保留备份并输出日志 | 不自动恢复数据库;结合迁移兼容性决定镜像或数据库恢复方案 |
| Yohaku 构建失败 | 服务器 release 不变 | 检查上游变更、依赖和构建日志 |
| Yohaku 新 release 启动失败 | 恢复旧软链接、重启并复检 | 若旧版本也未恢复,检查容器挂载、.env、端口和日志 |
网页正常但 WebSocket 非 101 | 不视为完整成功 | 检查 /ws/ 反向代理、CDN 和 Core 日志 |
| 定时任务长时间未运行 | 无更新动作 | 检查 1Panel 任务状态、GitHub Actions 是否被暂停及时区配置 |
6.1 PostgreSQL 备份可读性抽查
至少每月执行一次:
能列出归档目录,说明备份至少可以被 pg_restore 识别。这不等同于完整恢复演练,但比只检查文件大小更可靠。
6.2 Yohaku 人工回退
自动回退失败或需要主动回退时:
回退后仍需完成公网路由和 WebSocket 检查。
七、首次启用后的观察周期
- 第一天:手动执行 Core 脚本和 Yohaku workflow,完成全量验收。
- 第二天:检查 1Panel
03:00的执行记录和 GitHub Actions03:30的运行记录。 - 连续观察 3 天:确认无更新时不会重启;有更新时迁移、健康检查和通知均正常。
- 稳定后每周:抽查任务记录、容器状态和磁盘占用。
- 稳定后每月:验证一次 PostgreSQL 备份可读性,并检查 Yohaku release 数量。
八、快速检查清单
首次启用前
-
docker compose config --quiet通过。 - Core Ping 返回
pong。 - Yohaku 本机端口
2323可访问。 - 三个公网关键路由均返回
200。 - WebSocket 返回
101 Switching Protocols。 - Yohaku 的
current与server.js软链接正确。 - 1Panel Node.js Runtime 已导出
.env,且PORT=2323。 - 1Panel 与 GitHub 的失败通知已开启并可接收。
每次实际更新后
- Core、PostgreSQL、Redis 与 Yohaku 状态正常。
- 本次 Core 更新的迁移结果已在 1Panel 报告或
/opt/mix-space/logs/core-update.log中确认成功。 - 本机 Core 和 Yohaku 健康检查通过。
- 公网首页、后台和 Ping 均返回
200。 - Webhook
health_check为200且success=true。 - WebSocket 返回
101。 - 已记录 Core 镜像摘要、Yohaku release 与 Actions run ID。
九、参数速查
| 项目 | 值 |
|---|---|
| Mix Space 目录 | /opt/mix-space |
| Yohaku 发布根目录 | /opt/yohaku |
| Core 镜像 | innei/mx-server:<APPROVED_VERSION> |
| Core 本机端口 | 127.0.0.1:2333 |
| Yohaku 本机端口 | 127.0.0.1:2323 |
| Core Cron | 0 3 * * *(服务器时区为 Asia/Shanghai) |
| Yohaku Cron | 30 19 * * *(UTC,对应北京时间次日 03:30) |
| Core 备份保留期 | 14 天 |
| Yohaku release 保留数量 | 5 个 |
| 健康检查上限 | 36 次 × 5 秒,约 3 分钟 |
参考资料
参考文章用于补充 1Panel 的界面操作与部署背景;涉及镜像、服务结构和健康检查的技术细节,以 Mix Space 官方文档和当前部署的 Compose 配置为准。