# 21 domainCheck 海外主机集中运维与自动化方案 如果当前你不是在做“为什么要这么设计”的方案评审,而是已经进入真实收口、准备上线阶段,建议先跳转: - `docs/25_domainCheck_海外单脑控制面上线收口总表.md` - `docs/23_domainCheck_终局运维架构设计_海外单脑控制面.md` - `docs/24_domainCheck_NodeAgent协议与ReleaseHub设计.md` ## 一、为什么要升级成“集中运维” 这段时间的多机联调已经证明一个事实: - 现在这套“人在海外主机上看后台,再去大陆机器上手工跑命令、复制日志、判断状态”的方式,能联调,但效率很低 - 一旦节点数从 `2` 台增加到 `3` 台、`5` 台、`10` 台,复杂度会快速失控 - 国内机器上又不能稳定部署 Codex,因此不能指望每台机器都具备“本机智能调试能力” - 检测日志很大,靠人工复制日志片段,不适合做持续诊断 所以后续不应该继续堆更多“检查脚本”,而应该把整个体系升级成: > 海外主机作为唯一运维控制面,统一接管大陆机器的安装、更新、重启、巡检、日志回流和故障诊断。 一句话目标: > 只在海外主机操作,大陆机器尽量不需要人工登录。 --- ## 二、最终目标形态 ### 1. 海外主机承担什么 海外主机作为唯一控制面,承担: - Web 后台 - API 控制面 - 运维任务中心 - 发布包仓库 - 节点注册与权限中心 - 日志汇聚与诊断入口 - 远程命令编排 - 巡检结果展示 也就是说,后续所有动作都从海外主机发起: - 新机器纳管 - 初始化安装 - 发布更新 - 配置下发 - 服务重启 - 健康检查 - 采集诊断包 - 远端日志查看 - 故障一键排查 ### 2. 大陆机器承担什么 大陆机器不再承担复杂控制逻辑,只承担: - `domaincheck worker/controller` 本体服务 - 一个轻量 Node Agent - 本机 systemd / 日志 / 版本 / 健康信息暴露 - 接收控制面任务并执行 - 将执行结果、日志、诊断包回传到海外主机 这意味着大陆机器以后是“被管理对象”,而不是“人工登录操作对象”。 --- ## 三、推荐方案 ## 方案 A:海外控制面 + 大陆 Node Agent 这是我建议的主方案,也是长期最优方案。 ### 核心思想 不要把“SSH 到每台机器执行命令”作为主链路,而是让每台大陆机器常驻一个 Agent: - Agent 主动连海外控制面 - Agent 拉取待执行任务 - 本地执行 systemd / shell / 发布 / 巡检 - Agent 把 stdout / stderr / 状态 / 日志游标回传 这样做的好处是: - 不要求海外机能直接入站打通到大陆机 - 不要求每次人工 SSH - 不怕 SSH 权限、跳板机、端口变化导致整套流程断掉 - 天然适合 NAT、弱网络、多机扩容 ### 交互方式 建议 Agent 使用下面其中一种方式主动连海外控制面: #### 首选:HTTPS 长轮询 - `agent -> overseas-api` - 周期拉取任务 - 周期上报心跳、版本、服务状态、日志摘要 优点: - 实现最简单 - 最容易兼容现有 Python / FastAPI 架构 - 容易先落 MVP #### 可升级:WebSocket 常连 - 建立长连接 - 海外控制面可实时下发任务 - Agent 实时回传执行日志 优点: - 更实时 - 日志流式体验更好 缺点: - 第一版复杂度更高 ### 为什么 Agent 比 SSH 更优 SSH 适合作为: - 首次 bootstrap - 临时人工兜底 - 非常规应急 但不适合作为日常主运维链路,因为: - 节点一多,权限和连通性管理会变得脆弱 - 脚本回显、超时、日志采集很难标准化 - 人工 SSH 本质上还是“远程手工运维” 所以最佳做法是: - SSH 只用于首次纳管 - 日常统一走 Agent ## 三点五、当前已经落地的第一版操作闭环 这套方案现在已经不只是设计稿,仓库里已经有一批可以直接使用的统一入口: - `domain-api/deploy/multi-region/init_ops_center_config.sh` - `domain-api/deploy/multi-region/drive_ops_center.sh` - `domain-api/deploy/multi-region/drive_release_hub.sh` - `domain-api/deploy/multi-region/drive_ops_action.sh` - `domain-api/deploy/multi-region/build_node_agent_bootstrap_plan.sh` 推荐从海外控制面按这个顺序使用: ### 1. 初始化控制面配置 ```bash cd /opt/domaincheck/domain-api bash domain-api/deploy/multi-region/init_ops_center_config.sh \ /etc/default/domaincheck-ops-center \ http://121.204.244.188:8100 \ http://152.53.37.118:8100 \ https://api.example.com ``` ### 2. 查看当前统一配置 ```bash bash domain-api/deploy/multi-region/drive_ops_center.sh config ``` ### 3. 在控制面本机生成发布包 ```bash bash domain-api/deploy/multi-region/drive_ops_center.sh release-package bash domain-api/deploy/multi-region/drive_ops_center.sh release-launchpad bash domain-api/deploy/multi-region/drive_ops_center.sh release-preview bash domain-api/deploy/multi-region/drive_ops_center.sh release-preview-smart worker bash domain-api/deploy/multi-region/drive_ops_center.sh release-show ``` ### 4. 导出一份联调/交接报告 ```bash bash domain-api/deploy/multi-region/drive_ops_center.sh doctor-export ``` ### 5. 为新节点导出接管计划 ```bash bash domain-api/deploy/multi-region/drive_ops_center.sh agent-plan-export \ /opt/domaincheck/domain-api/runtime/ops-center-reports/agent-plans \ http://127.0.0.1:8100 \ mainland-worker-02 \ mainland \ worker \ https://api.example.com \ /opt/domaincheck ``` 这五步对应的意义分别是: - 先统一控制面默认地址和身份 - 再确认驾驶舱当前在看哪个环境 - 再把发布物、发布前预检和发版驾驶舱都收回统一入口,不再额外记根目录脚本 - 再把现场收敛成可以回看、可以交接的报告 - 最后为新增节点生成标准接管方案 这样后面无论是海外 Codex 自动驾驶、后台按钮,还是人工运维,都不再需要先去大陆机器手工拼命令。 ## 三点六、现在发布驾驶舱已经进入统一数据口径 目前发布侧也已经不是零散接口拼出来的状态,而是收敛成了一套统一判断: - `GET /api/v1/ops/releases/launchpad` - `ops overview -> release_hub.launchpad` - `check_release_hub.sh` - `drive_release_hub.sh launchpad` - 运维中枢页面里的“发布驾驶舱” 这几处现在复用的是同一套结论,都会统一告诉你: - 当前是 `ready / attention / blocked` - 最新发布包是否可用 - 最新 Release 是否已经建立 - Worker 智能灰度是否可发 - Control 发布是否可发 - 下一步推荐动作是什么 同时,`GET /api/v1/ops/runbook` 里的标准作业路径 `release_progression` 也已经切到同一套发布驾驶舱判断。 也就是说,海外控制面看到的“标准作业路径”和“发布驾驶舱”不会再出现一套说能发、一套说先补接管的分裂口径。 现在又往前推进了一步: - `POST /api/v1/ops/runbook/sequences/{sequence_key}/execute` 后台上的标准作业路径按钮,后续都应该优先走这个入口,再由后端统一分发到 driver action / playbook / rollout 预案,而不是前端自己维护动作分支。 这样后续海外 Codex、后台按钮和命令行脚本拿到的就不再是三套不同口径,而是同一套“发布驾驶判断”。 ## 三点七、现在回执队列也已经进入统一治理入口 除了发布驾驶舱,Node Agent 回执队列这一层现在也已经不再是“只能看、不能管”的状态。 当前已经统一收口成三类入口: - 页面: - OpsCenter 托管节点表可以直接打开“回执队列治理”抽屉 - 驾驶建议: - `dead_letter / retrying` 会优先落到标准动作模板 - 海外单入口 CLI: - `drive_ops_center.sh queue-status` - `drive_ops_center.sh queue-records` - `drive_ops_center.sh queue-flush` - `drive_ops_center.sh queue-replay` - `drive_ops_center.sh queue-replay-record` - `drive_ops_center.sh queue-discard-record` 这意味着海外主机已经可以统一处理: - 哪台节点存在积压 / 死信 - 头部记录是什么 - 什么时候应该立即冲刷 - 什么时候应该重放 - 什么时候应该说明原因后丢弃 当前阶段仍然明确限制为: - `record_visibility=head_only` - 所有治理动作都落成正式 `ops job` - 不直接 SSH 到节点改队列文件 这样以后即使把远端全量死信记录正式投影到控制面,也只是“扩可见范围”,而不是重新推翻当前模型。 --- ## 四、这套方案要解决的具体问题 ## 1. 安装部署自动化 目标: - 海外控制面点一次“新增节点” - 填一个节点模板 - 大陆机器自动初始化 建议流程: 1. 海外后台新增节点 2. 生成 `bootstrap token` 3. 大陆机器只执行一次极短安装命令 4. Node Agent 注册到海外控制面 5. 控制面向该节点下发: - 拉取发布包 - 解压 - 生成 `/etc/default/...` - 安装 systemd - 启动服务 6. 回传安装结果 这样后续加机器时,不需要再重复人工对照文档逐条敲。 ## 2. 更新发布自动化 目标: - 海外主机统一推版本 - 大陆节点自动拉包、灰度更新、失败回滚 这里强烈建议: > 后续不要让大陆机器自己跑 git 作为正式更新链路。 而是改成: - 海外控制面构建发布包 - 版本号固定 - Agent 下载指定 release 包 - 校验 checksum - 切换当前版本软链 - 重启服务 - 回传成功/失败 这样比远程 `git pull` 更稳,因为: - 不依赖每台机器 git 权限 - 不怕工作区脏文件 - 不怕 root/www 用户混用 - 可回滚 推荐目录形态: ```text /opt/domaincheck/releases// /opt/domaincheck/current -> /opt/domaincheck/releases// ``` 更新时: - 下载新版本到 `releases` - 校验 - 切换 `current` - `systemctl restart ...` 失败就回滚软链。 ## 3. 远程命令执行自动化 目标: - 海外控制面能发“结构化任务” - 不再让人手工复制命令 建议任务类型: - `service.start` - `service.stop` - `service.restart` - `service.status` - `deploy.release` - `config.render` - `diagnostics.collect` - `logs.tail` - `script.run` - `health.check` 每个任务统一回传: - 任务 ID - 节点编码 - 开始时间 / 结束时间 - exit code - stdout - stderr - 结构化结果 JSON 这样后面后台才能真正做“操作中心”。 ## 4. 日志集中回流 目标: - 海外后台就能看到大陆机器日志 - 不再人工抄 `journalctl` ### 日志回流建议分三层 #### A. 关键事件流 只回传关键事件: - 服务启动 - 服务重启 - 任务开始 - 任务完成 - 代理刷新失败 - Redis/DB 连接异常 - 第三方站点异常 适合默认长期开启。 #### B. 诊断模式日志流 像你现在提的“关闭 / 关键 / 全量回传”一样: - `off` - `key` - `full` 这是正确方向,应该继续保留。 #### C. 诊断包 当出现疑难问题时,一键打包: - 最近 N 分钟 `journalctl` - `runtime/status` - `runtime/cluster` - `detect_worker.log tail` - `/etc/default/*` - 当前版本号 - 本机健康检查输出 然后上传海外主机。 这比全量实时传所有日志更经济,也更适合定位问题。 ## 5. 健康巡检自动化 目标: - 每台大陆机自动自检 - 海外后台只看结果 建议 Agent 每 30 秒到 60 秒上报: - 节点在线状态 - 当前版本 - API / Worker / Sync Agent 运行态 - Redis / PostgreSQL / 磁盘 / 内存 / CPU - 最近告警 - 当前任务负载 - 最近日志时间 并把现有脚本升级为 Agent 内部检查项: - `check_mainland_controller.sh` - `check_mainland_worker.sh` - `check_temp_topology.sh` - `check_worker_participation.sh` 后续不是人工执行这些脚本,而是 Agent 周期性执行并结构化上传结果。 --- ## 五、建议的系统分层 ## 1. 海外控制面 建议新增一个“运维控制模块”,逻辑上可放进 `domain-api`,后续再拆独立服务也可以。 ### 需要的核心对象 #### `managed_nodes` 记录纳管节点: - `node_code` - `region` - `role` - `hostname` - `ip` - `agent_version` - `current_release` - `status` - `ssh_enabled` - `agent_last_seen_at` - `tags` #### `ops_jobs` 记录运维任务: 建议以后直接以 [ops_job_contract.md](/www/wwwroot/getDomain/docs/schemas/ops_job_contract.md:1) 为正式母本。 - `job_id` - `job_type` - `target_nodes` - `payload` - `created_by` - `status` - `started_at` - `finished_at` #### `ops_job_steps` 记录每个节点执行步骤: - `node_code` - `step_name` - `status` - `stdout` - `stderr` - `result_json` #### `node_log_streams` 记录日志游标和日志回流状态: - `node_code` - `source` - `mode` - `cursor` - `last_received_at` ## 2. Node Agent 建议单独做一个轻量 Python 服务,比如: ```text domaincheck-node-agent ``` 职责: - 周期心跳 - 拉取任务 - 本地执行 - 采集日志 - 上报结果 - 生成诊断包 Agent 尽量独立于业务主程序,不要把它耦合进 `detect_worker.py`。 原因: - 运维系统不能依赖业务进程是否正常 - 即使 Worker 崩了,Agent 还应该活着,才能帮你排障 --- ## 六、对你当前项目最合适的落地路线 ## 第一阶段:先做“控制面集中化” 目标: - 海外后台统一看到所有大陆机器 - 一键拉诊断 - 一键执行已有检查脚本 - 一键切日志回传模式 这个阶段先不碰太多发布链路,优先把“看”和“查”统一。 ### 交付物 - Node Agent MVP - 海外后台“节点管理”页 - 海外后台“运维任务”页 - 海外后台“远端日志”页 - 海外后台“诊断包”页 ## 第二阶段:再做“一键更新” 目标: - 海外控制面选择版本 - 指定节点灰度发布 - 自动回滚 ### 交付物 - 发布包生成器 - `release manifest` - Agent 下载 / 校验 / 切换版本 - 回滚机制 ## 第三阶段:再做“一键安装新节点” 目标: - 新机器只执行一次 bootstrap - 其余全部由海外控制面接管 ### 交付物 - bootstrap token - 安装向导 - 节点注册流程 - 环境模板生成器 --- ## 七、比“SSH 全接管”更优的地方 你提的方向是: > 海外主机配置好 SSH,后续所有大陆机器都由代码内部接管 这个方向本身是对的,但如果只做“SSH 全接管”,还不够优秀。 更优解是: > SSH 只作为纳管和兜底方式;日常统一走 Agent 主动连接。 这样好处是: - 架构更稳 - 不依赖每次远程入站打通 - 不怕某些网络环境 SSH 不稳定 - 更适合未来节点继续增加 - 更容易做权限分级、审计、结果留痕 所以我建议最终定成: ### 运维主链路 - `海外控制面 -> Agent 任务编排 -> 大陆节点执行 -> 回传结果` ### 运维兜底链路 - `海外控制面 -> SSH -> 大陆节点` --- ## 八、和现有代码如何衔接 当前项目已经有一些很好的基础,不需要推翻: - 多机节点模型 - `runtime/status` - `runtime/cluster` - `sync-summary` - 一批巡检脚本 - 日志回传开关雏形 - 运行中心 这些都应该保留,并演进成: ### 当前脚本的未来定位 - `bootstrap_*.sh` - 保留为 bootstrap / 应急工具 - `check_*.sh` - 演进成 Agent 内部的标准诊断动作 - `runtime/status` - 继续作为统一运行态接口 - `runtime/cluster` - 继续作为统一集群视图 - `detect_result_projection / runtime_projection` - 继续作为跨地域观测基础 也就是说,现有代码不是废掉,而是从“人工脚本时代”升级成“控制面编排时代”。 --- ## 九、我建议的最优落地决策 如果只选一个方向,我建议直接定成: ### 最优方案 - 海外主机为唯一控制面 - 大陆节点统一部署 `domaincheck-node-agent` - Agent 主动访问海外控制面 - 日常安装、更新、巡检、日志回流全部走 Agent - SSH 仅保留为 bootstrap 和应急手段 - 正式更新统一改为 release 包分发,不再把 `git pull` 作为正式更新链路 这是当前最值得投入的方向,因为它能同时解决: - 调试效率低 - 多机管理复杂 - 权限混乱 - 日志分散 - 更新不稳定 - 新增节点成本高 --- ## 十、建议的下一步执行顺序 不要再继续先补散点 bug,而是先把运维骨架建起来。 建议顺序: 1. 固化这份方案 2. 新建 `node-agent` 设计草案 3. 先做 Agent MVP 4. 先接入: - 心跳 - 远程任务 - 诊断包 - 日志 tail 5. 海外后台新增: - 节点管理页 - 运维任务页 - 远端日志页 6. 再把现有检查脚本封成 Agent 动作 7. 最后再做发布链路自动化 --- ## 十一、结论 当前最优策略不是“继续加脚本”,而是: > 把 domainCheck 从“多机联调项目”升级成“海外控制面统一接管大陆节点的自动化运维系统”。 从长期看,这会比继续靠人工 SSH、人工复制日志、人工比对状态高效很多,也更符合你后续继续扩机器的目标。