
如果你手里只有一两台带 GPU 的机器SSH 上去敲几行nvidia-smi完全够用。但当机器的数量上来之后光靠人肉 SSH 巡检就撑不住了。我去年接手一个混着 3090、4090、A5000 的八台 GPU 机群那段时间最大的体会就是缺一套能统一监控、调度、自动恢复的开源框架。和同事调研一圈之后我选择了 openrig把整条链路切过去之后夜里终于能睡个踏实觉了。这篇内容不是 openrig 的官方文档复述而是我基于真实交付环境整理的部署与使用记录。如果你也管理多台 GPU 工作站、渲染节点或小型训练集群正被每台机器都要单独登录查看任务卡死没人知道显卡利用率参差不齐这类问题困扰那这篇文章应该能帮你省下不少时间。我会从为什么选它、怎么部署、内部机制怎么运作到实际跑起来踩过的坑一步步拆开讲。1. 从人肉巡检到统一框架openrig 解决的痛点1.1 散养 GPU 机群的真实状态先说个场景。八台机器分布在三个机房型号还不一样有的是双卡 4090有的是四卡 A5000还有一台老旧的 2080 Ti 在角落吃灰。表面上这没什么但真跑起业务来就是另一回事了。我之前的日常大概是这样的早上到工位先 SSH 登录第一台机器执行nvidia-smi --query-gpuutilization.gpu,memory.used,temperature.gpu --formatcsv记录一下然后退出登录第二台再记录然后第三台……等八台都跑完半小时过去了。这还只是看一眼状态。如果发现某张卡利用率很低还得手动排查是任务跑完了、还是代码卡住了、还是有人在上面偷偷跑了别的东西。这还不是最折磨人的。最折磨人的是半夜。之前有一回一台机器上的渲染任务因为显存分配失败挂住了进程还在但实际已经不再产出任何结果。我第二天早上才发现等于整整浪费了一个通宵的机时。这类进程存活但业务停滞的问题SSH 巡检很难及时发现。后来我逐渐形成了一个经验超出一台机器之后绝大多数 GPU 运维问题都不是硬件坏了而是状态不可见。不知道哪张卡是闲置的不知道哪个任务在空转不知道哪台机器快把磁盘写满了那所有调度决策都是瞎猜。openrig 说白了就是来解决这个问题的它把一个机群的硬件资源、运行任务、健康状态集中到一个视图里并且能根据预设策略自动做点事情。1.2 openrig 的定位不只是监控面板很多了解过监控方案的人看到 openrig 的第一反应是这不就是个带界面的 nvidia-smi 吗我第一次接触时也是这么想的但实际用下来发现定位完全不一样。openrig 的核心不是看而是管。它由三个角色构成openrig-server控制中心负责收集所有节点的状态、分发任务、执行自愈策略、暴露 API 和面板。openrig-agent部署在每台 GPU 机器上负责采集本机硬件数据、执行服务端下发的命令、上报心跳。openrig-cli命令行客户端把管理指令发给 server支持查看节点、提交任务、调整策略等。简单点说它是把监控、任务调度、故障自愈这三件事揉在了一起。监控给的是眼睛调度给的是手自愈给的是最简单的应激反应。大多数自建方案往往只做到了第一项后两项完全靠人肉补齐。而 openrig 至少在自动做决策这一点上给了我一个可以落地的框架。举个例子。之前我需要每周手动清理一次显存残留进程因为很多训练脚本退出的时候不会干净释放显存。用 openrig 之后我在 agent 的配置里打开了一个名为gpu_residual_clean的选项它可以识别出哪些进程是没有对应父任务的残留进程然后按策略选择是告警还是自动清理。这种能力单靠 Prometheus 那套采集链路是做不到的因为它涉及对进程生命周期的判断而不仅仅是数值采集。1.3 和自拼 Prometheus Grafana 方案比差在哪我之前也尝试过用 Prometheus node_exporter dcgm_exporter Grafana 拼一套监控。说实话面板做出来之后确实很好看各种曲线都很丝滑。但用了一段时间之后我发现这套方案有几个绕不开的问题对比维度自拼 Prometheus Grafanaopenrig数据采集只能拿到 exporter 暴露的数值指标除了指标还采集进程级信息和任务状态故障处理只能配置告警规则收到告警后人肉处理支持预设自愈动作自动隔离/重启/恢复任务管理不涉及需要另接调度器自带轻量任务管理能提交和跟踪任务部署维护组件多exporter、prometheus、grafana 都要各自维护一个 server、每个节点一个 agent简单很多上手成本需要理解 PromQL、告警规则、exporter 指标语义一个配置文件加几条命令即可倒不是说 Prometheus 方案一无是处。如果你已经有成熟的 Prometheus 体系openrig 也可以把指标吐给 Prometheus 做长期归档。但如果你像我一样核心诉求是把机群管起来而不是画一堆图那 openrig 这种一体化的思路确实更顺手。2. 部署前先想清楚架构server 和 agent 如何分工2.1 为什么一定要拆成控制端和代理端刚开始我自己写管理脚本的时候最大的失误就是没有拆分控制端和执行端。那时候我是从一台管理机上通过 SSH 连到所有机器去执行命令脚本里全是ssh userhost nvidia-smi ...这样的行。看起来能跑实际上脆弱得不行只要管理机和目标机器之间网络稍微抖动或者目标机器的 SSH 连接数超限整个脚本就卡在那里不动了。openrig 的架构拆成 server 和 agent 之后通信模型完全变了agent 主动往外连而不是 server 往里连。这里有个容易被忽视的好处你不需要在所有机器上开放 SSH 入站给管理机agent 只要能够访问到 server 的端口就行。对于跨机房甚至跨公网的部署场景这个模型要安全得多。另外agent 是常驻进程它自己会采集数据、检测异常、执行本地操作。就算和 server 的连接暂时断开agent 依然能独立做一些本地保护动作比如温度过高时降频、磁盘写满时清理临时文件。这就避免了中心化控制最怕的故障场景——控制端挂了所有节点跟着失明。2.2 网络规划与端口约定部署之前建议先把网络规划好。我踩过的最蠢的坑就是server 默认端口被同一台机器上的其他服务占用了导致 agent 一直连接不上我还在怀疑配置文件写错。openrig 的端口约定不复杂server 监听端口7820/tcp所有 agent 和 cli 都连这个端口。agent 上报端口agent 不监听端口它主动向 server 的7820发起长连接。Web 面板端口7821/tcp可以在 server 配置文件里关掉单独挂到反代后面。我自己的习惯是server 单独放一台 2C4G 的小机器上所有 GPU 节点都只开7820的出站访问。Agent 的配置里写 server 地址时建议写内网 IP 而不是域名省得 DNS 出问题。还有一个小细节如果节点和 server 之间有防火墙要同时放行 TCP 和 UDP。Agent 握手阶段会先用 TCP 建立主连接但后续可能用 UDP 做轻量心跳别把 UDP 封了然后排查半天。2.3 配置文件这样写后续才不折腾openrig 的配置分成 server 端和 agent 端都用 YAML 格式。我见过不少人部署的时候图省事全部用默认参数跑结果上线之后各种难受。下面这份是我目前在用的 server 配置关键字段都有注释# /etc/openrig/server.yaml server: listen: 0.0.0.0:7820 data_dir: /var/lib/openrig panel: enabled: true listen: 0.0.0.0:7821 agent: heartbeat_interval: 15 # agent 每隔 15 秒上报一次心跳 heartbeat_timeout: 90 # 连续 90 秒没收到心跳节点标记为离线 reconnect_backoff: true # 断线重连采用指数退避避免同时重连风暴 scheduler: policy: gpu_memory_first # 任务放置策略优先塞进显存余量最大的节点 reserved_memory_percentage: 10 # 每张卡保留 10% 显存不做分配防止 OOM max_restart_count: 2 # 自愈模块对单个任务的最大重启次数 alert: webhook: endpoints: - url: https://example.com/webhook/openrig events: [node_offline, gpu_overtemp, task_failed]这里我想解释两个容易被忽略的字段因为它们在后续实际运行中帮了我大忙。第一个是heartbeat_timeout。默认值是 45 秒但我调到了 90 秒。后面我会专门讲这 45 秒在跨机房网络下太容易误报了。第二个是reserved_memory_percentage这个非常关键。很多调度器默认把显存塞得满满的结果任务启动的时候系统还要吃点显存做上下文直接 OOM。保留 10% 之后虽然单卡利用率上限降了一点但整体稳定性高了很多任务失败率明显下降。agent 端的配置简单一些核心是三个东西# /etc/openrig/agent.yaml server: address: 192.168.10.10:7820 token: YOUR_NODE_TOKEN collector: interval: 5 # 本机硬件数据采集间隔 gpu_metrics: true # 采集显存、利用率、温度、功耗 process_metrics: true # 采集 GPU 上的进程列表及显存占用 disk_metrics: true # 采集磁盘容量和 inode 余量 local_protect: enable_gpu_overtemp_protect: true overtemp_threshold: 87 # GPU 温度超过 87℃ 时主动降频保护agent 端的local_protect是我非常看重的一个能力。它意味着即使 server 完全失联agent 仍然会在本地做保护动作。对于无人值守机房这一层兜底比任何花哨的远程告警都实在。3. 从零到一openrig 多节点环境搭建实录3.1 前置条件驱动、容器、系统服务在正式部署 openrig 之前需要确认每台 GPU 机器的基础环境。我踩过最大的坑是某台机器的显卡驱动是老的 470 系列openrig 通过 NVML 采集温度、功耗、显存信息的时候部分字段读不到导致面板上显示一堆 NaN。所以我的建议是先把所有机器的驱动版本统一一下。不用追最新但要保证在同一个大版本内。比如统一用 535 或 550 系列驱动配 CUDA 12.x 都行。检查方法很常规nvidia-smi看右上角 Driver Version 即可。如果版本太老建议先升级驱动再部署 openrig。不要指望监控工具能绕过驱动层去读硬件信息NVML 就是兜底方案。另外openrig 的 agent 默认通过 Docker 或 Podman 拉起任务容器。如果机器上还没有装容器运行时需要先装好。我这边用的是 Docker Engine nvidia-container-toolkit。装完可以用一条命令验证docker run --rm --gpus all nvidia/cuda:12.1.0-base-ubuntu22.04 nvidia-smi看到 GPU 信息正常输出就说明容器能访问显卡了。这一步如果过不了后面 openrig 的任何任务调度都会在启动容器时失败而且错误提示可能不太直观。3.2 部署 openrig-server 并初始化server 端的部署比我预想的简单。从项目的 release 页面下载对应架构的二进制包解压之后把生成的openrig-server放到/usr/local/bin/下再写一份配置文件mkdir -p /etc/openrig /var/lib/openrig wget release包地址 tar xzf openrig-server-*.tar.gz cp openrig-server /usr/local/bin/ cp conf/server.yaml /etc/openrig/server.yaml然后生成初始 token这个 token 是后续每个 agent 加入时需要带的凭证openrig-server --generate-token输出是一长串随机字符串把它记下来填进 agent 的token字段。接着初始化数据目录并启动服务openrig-server --config /etc/openrig/server.yaml --init systemctl enable openrig-server systemctl start openrig-server注意--init只执行一次它会创建数据库文件、默认告警通道和一些初始配置。重复执行可能会重置数据别手滑。启动之后可以快速验证一下服务状态curl -s http://127.0.0.1:7821/api/v1/health如果返回{status:ok}之类的结果说明 server 起来了。Web 面板这时也能访问了用浏览器打开http://server_ip:7821能看到一个空的控制台等 agent 接入之后就会陆续出现节点信息。3.3 为每台 GPU 机器部署 agentagent 的部署可以批量做也可以一台台手动来。机器少的时候我推荐手动因为每台机器的配置细节可能不同比如节点名称、采集间隔、是否需要本地保护等。之后再上更多机器时再用 Ansible 批量铺。单台机器的部署流程wget agent包地址 tar xzf openrig-agent-*.tar.gz cp openrig-agent /usr/local/bin/ cp conf/agent.yaml /etc/openrig/agent.yaml然后修改 agent 配置把 server 地址和 token 填上server: address: 192.168.10.10:7820 token: 你生成的TOKEN启动 agentsystemctl enable openrig-agent systemctl start openrig-agentagent 起来之后它会自动向 server 注册。在 server 的 Web 面板上或者通过 CLI就能看到新节点状态变成online。这里有个值得注意的点agent 注册之后server 默认不会自动给它分配任务除非你把它加入一个调度池。这设计是合理的因为有些机器可能就是专门给某个团队用的不应该被全局调度器随便占用。把机器加入调度池的命令也很简单openrig node set-pool --node 10.2.3.4 --pool default --enabled true3.4 第一个节点上线后的验证清单第一个节点接入后不要急着跑大任务先在面板上核对几个信息避免后面出问题还要回头排查节点状态是否为online心跳时间戳是否在持续刷新。GPU 列表中每张卡的型号、显存容量、驱动版本是否和实际一致。温度和功耗有没有实际数值是不是 NaN。在节点详情页能看到当前 GPU 上运行的进程列表如果没有任务应该是空的。如果这些都没问题就可以提交一个最小的测试任务试试调度链路openrig task run \ --node 10.2.3.4 \ --gpu 1 \ --image nvidia/cuda:12.1.0-base-ubuntu22.04 \ --cmd nvidia-smi任务跑完之后在面板的任务列表里应该能看到状态变成completed并且日志里有 nvidia-smi 的输出。这一步验证通过基本上整个 agent 到 server 的链路就已经通了。之后你再提交真实任务就只是命令和镜像层面的区别。4. 核心机制拆解数据采集、调度和自愈是怎么协同的4.1 采集层为什么不用现成的 dcgm_exporter很多人问过一个问题openrig 的采集层为什么不用 DCGM 那套DCGM 是 NVIDIA 官方的数据中心 GPU 管理方案dcgm-exporter配合 Prometheus 也确实能拿到很完整的指标。我的看法是DCGM 指标丰富但偏向硬件健康与性能而 openrig 需要的采集维度里有一部分是进程级和任务级的。比如某个 GPU 上跑了哪些进程、每个进程占多少显存、这个进程是不是某个任务容器的子进程。这些信息从 DCGM 里拿不到只能通过 NVML 的进程枚举接口外加对容器运行时 PID 空间的映射来拿。openrig agent 的采集器默认做这几件事调用 NVML 获取每张卡的利用率、显存、温度、功耗、风扇转速。枚举每张卡上的进程列表记录 PID、显存占用、进程名。读取系统层的磁盘、内存、负载、inode 使用率。将容器运行时Docker/Podman的容器列表和 GPU 进程做关联确定每个进程属于哪个任务。每个采集周期默认 5 秒一次。这个间隔是经过权衡的太快会增加 agent 的 CPU 开销太慢又会让调度器对显存变化的感知滞后。对于绝大多数训练和渲染场景5 秒足够。4.2 调度层资源预留和任务放置逻辑openrig 的调度策略不像 Kubernetes 那么复杂它更轻量。它要解决的问题很明确来了一个任务需要几张卡、多少显存和多少 CPU应该放到哪台机器上。默认的gpu_memory_first策略规则大致是这样的在所有在线且处于调度池内的节点中过滤掉不满足最小显存要求的节点。对剩余节点按当前空闲显存总量排序空闲多的优先。在单节点内部按满足任务显存需求的卡中显存余量最小者优先的方式选卡这样可以尽量把显存碎片压到最低。我特别喜欢显存余量最小者优先这个细节。很多调度器会倾向于把任务分散到不同机器上结果每台机器都剩一些碎显存最终谁也没法跑大任务。而 openrig 这种同类任务尽量聚堆的思路反而能腾出一整台干净的机器给后面的大任务。资源预留和调度是两件事。openrig 在调度时会把reserved_memory_percentage考虑进去所以不会出现任务刚启动就 OOM的情况。我设置的 10% 预留主要覆盖两类开销一是容器运行时和驱动层自己吃的显存二是 PyTorch 等框架的缓存预分配。实测下来训练任务的失败率降低了不少。4.3 自愈层先隔离、再重启、后恢复openrig 的自愈模块是我最终决定长期使用它的理由。它执行任何恢复动作之前都会先做一个隔离。什么意思比如某张卡温度到了 90 度自愈模块不会立刻杀掉上面正在跑的任务而是先把这张卡标记为不健康让调度器不再往这张卡上分配新任务同时通知正在运行任务的容器暂停下来。确认温度降下来之后再恢复执行。这个先隔离再恢复的过程避免了最坏的情况任务正在写 checkpoint 写到一半GPU 被强制重启写坏了文件。我在生产环境见过太多因为探测到异常就直接 kill导致的二次故障所以特别认可这种稳妥的处理方式。自愈模块支持的策略类型包括node_offline_alert节点离线只告警不动作。gpu_overtemp_isolateGPU 温度超限隔离该卡并暂停相关任务。task_failed_restart任务失败且配置允许重启时自动重启最多max_restart_count次。disk_space_low_vacuum磁盘空间不足时清理指定目录下的临时文件。每个策略都可以在 server 配置里单独开关。我建议最开始只开告警和隔离不要开自动重启。等你对任务行为和数据落盘情况足够了解之后再放开自动重启。4.4 时序数据存储与留存策略openrig 会把采集到的指标写到自己的时序数据库里。默认存储位置是 server 机器的/var/lib/openrig目录。这里有一个很容易被忽略的问题如果不设保留策略时间长了磁盘会被写满。我之前就遇到过跑了两个月之后一块 200G 的数据盘被指标数据填满了。推荐配置一个合理的保留周期。训练和渲染场景下15 天以内的 5 秒级数据是有用的超过 30 天的数据基本不会有人再看。我目前保留策略是这样的5 秒级原始数据保留 7 天。1 分钟聚合数据保留 30 天。5 分钟聚合数据保留 90 天。这样既保证了最近几天排查问题时有足够细的粒度又不会让磁盘无限膨胀。配置方式是在 server.yaml 里加一个 retention 段storage: retention: raw: 7d minute: 30d five_minute: 90d另外如果公司已经有一套 Prometheus也可以让 openrig 把指标远程写入到 Prometheus 里做长期归档。openrig 在 server 端内置了/metrics接口用 Prometheus 的 remote write 或者直接按 scrape 方式拉取都可以。我自己是把 openrig 接入 Prometheus 的长期趋势图还是 Grafana 更顺手。5. 真实跑起来之后踩过的四个坑5.1 坑一心跳超时误判网络小抖动把节点踢下线上线第一周我就遇到了一个特别烦人的问题某台机器明明在正常跑任务openrig 面板却时不时把它标记成offline过几分钟又自动变回online。一开始我怀疑是 agent 挂了但登录到那台机器上看agent 进程好好的。后来排查网络日志才发现问题出在跨机房链路的网络抖动上。机房之间的专线偶尔会有几秒钟的延迟波动而 agent 每 15 秒发一次心跳包server 连续 45 秒没收到心跳就判定离线。一旦赶上两次心跳都卡在抖动窗口里节点就被误判了。这个问题的修复方案有两个层面我都做了一是把heartbeat_timeout从默认的 45 秒调到了 90 秒给网络抖动留出余量。二是把心跳模式从固定间隔改成了指数退避也就是 agent 发现心跳发送失败后会按 1 秒、2 秒、4 秒……的间隔重试而不是傻傻地等下一个 15 秒周期。经过这两项调整误报率从每天好几次降到了几乎为零。所以遇到这种问题先观察再调参不要一上来就怀疑 agent 坏了。5.2 坑二显存假占用残留进程让调度直接卡死有一次我发现一个奇怪现象某张 4090 的显存明明没任务在用却一直显示被占用了 12GB调度器死活不往这张卡上放新任务。登录到机器上执行nvidia-smi一看发现上面挂着一个已经没有父进程的 Python 进程占着显存不放。这类问题在长跑训练任务的机器上非常常见。任务容器异常退出后容器本身被清理了但某些子进程没有被 Kill 干净显存就被这些孤儿进程一直占着。普通的监控面板只能告诉你这张卡用了 12GB却区分不了这是健康占用还是残留垃圾。openrig 的 agent 上报进程信息时会额外标注这个进程是否属于当前活跃任务。如果进程的父进程已经不存在、容器也已经退出agent 就会把它标记为orphan。我在 agent 配置里打开了gpu_residual_clean选项让 agent 每天凌晨自动清理一次孤儿进程。打开之前最好先在手动模式下跑几天确认没有误杀正常进程再开启自动清理。手动清理的指令也很有用遇到紧急情况不必等定时任务openrig node vacuum --node 10.2.3.4 --gpu 2这条命令会列出该卡上的孤儿进程让你选择删除或保留。注意vacuum默认是交互式的直接加--force才会非交互执行。首次使用别用--force。5.3 坑三自动重启误杀了带 checkpoint 的训练任务这是让所有运维同学都血压飙升的一类问题。某个训练任务因为显存 OOM 异常退出了自愈模块按照配置自动拉起了一个新的容器。结果新容器从头开始训练旧容器写了一半的 checkpoint 被初始化操作覆盖掉了。十几个小时的训练进度归零。问题出在重启策略的粒度上。默认重启策略对所有任务一视同仁但实际任务差别太大了推理任务挂了重启完全没问题训练任务则需要考虑 checkpoint 的续跑能力。我的解决方案很简单在任务级别加一个protected标签标记为 protected 的任务不会被自愈模块自动重启只会告警。这样重要任务即便失败也只会通知到人由我手动决定怎么恢复。一个 openrig 任务提交示例openrig task run \ --node 10.2.3.4 \ --gpu 2 \ --image training-image:v2 \ --protected true \ --cmd python train.py --resume /data/checkpoints/latest.ckpt保护任务、手动处理听起来好像不如全自动高级但在真实生产环境里手动介入重要任务的失败恢复反而是最稳妥的做法。全自动化留给那些无状态、可随时重建的任务就好。5.4 一次完整排查链路从告警到定位再到修复踩了前面这些坑之后我总结出了一套自己的排查流程正好举个例子模拟一遍。假设一个工作日下午openrig 面板弹出告警node 10.2.3.4 GPU 3 overtemp isolat。我的步骤是这样的第一步先看告警详情。告警里自带节点 IP、GPU 索引、触发时的温度数值和持续时间。由此可以确认是温度超过 87 度持续 30 秒的硬告警不是瞬时尖峰。第二步打开节点详情页查看 GPU 历史曲线确认这张卡在过去一小时内的温度走势。如果曲线是缓慢上升的大概率是散热问题如果是突然跳上去的可能是任务负载突变。第三步看这张卡上正在运行的任务。openrig 的任务列表里能直接看到任务 ID、容器 ID 和启动时间。如果任务本身是视频渲染或模型训练负载高导致的升温就能解释通了。第四步检查同节点的其他卡是否正常。如果整机所有卡温度都在涨问题出在机房空调或机箱风道如果只有一张卡异常问题可能出在散热片、风扇或者硅脂上。我的处理结果是把该任务迁移到另一台机器上openrig 的任务迁移命令一条搞定然后给这张卡挂了一个维护标签让调度器暂时不往上面分配新任务。后续让现场同事检查了一下风扇确实有一个风扇转速异常。整个过程从告警到定位大概花了十分钟大部分时间消耗在确认现场和决策。和之前 SSH 登录逐台排查相比效率提升是数量级的。6. 把 openrig 接进现有运维体系告警、插件与二次开发6.1 通过 Webhook 把告警推到即时通讯工具openrig 自带一个简易的告警记录页面但没人会全天盯着页面看。好在它支持 Webhook可以把告警事件推送到任意支持 Webhook 的即时通讯工具里。我在 server.yaml 里配置了一个通用的 Webhook 端点告警消息以 JSON 格式 POST 出去。对于国内团队常用的钉钉/飞书/企业微信机器人只需要在中间加一层格式转换即可。我这里给一个简单的 Python 转换服务示例改造自标准 Webhook 接收器# webhook_forwarder.py import json import requests from flask import Flask, request app Flask(__name__) DINGTALK_WEBHOOK https://oapi.dingtalk.com/robot/send?access_tokenxxx app.route(/openrig-webhook, methods[POST]) def handle(): event request.get_json() if not event: return ok # 只转发关心的告警级别 if event.get(level) not in (warning, critical): return ok msg fopenrig 告警{event.get(event_type)}\n节点{event.get(node_ip)}\n详情{event.get(message)} requests.post(DINGTALK_WEBHOOK, json{ msgtype: text, text: {content: msg} }, timeout10) return ok if __name__ __main__: app.run(host0.0.0.0, port8090)这样一旦有节点离线、GPU 高温、任务失败等事件负责的同事立刻能在手机上收到消息。我自己的经验是告警消息里务必带上节点 IP 和事件类型不要只发一句话否则收到消息的人还得去翻面板。6.2 自定义指标采集风扇、电源和第三方传感器openrig agent 内置的采集器覆盖了 NVML 能拿到的指标但有些场景下还需要采集额外的数据。比如老机器的电源管理模块没有标准 NVML 接口只能通过 IPMI 工具读取或者机房里有温湿度传感器也想集中到一个面板里看。agent 有一个插件机制可以放置自定义采集脚本。把脚本放到/etc/openrig/plugins/目录脚本往 stdout 输出 JSON 格式的指标数据agent 就会自动收集并上报。一个简单的温度采集插件示例#!/bin/bash # /etc/openrig/plugins/ipmi_temp.sh temp$(ipmitool sensor get PCH_TEMP | awk /^PCH_TEMP/ {print $NF}) echo {\metric\: \ipmi_pch_temp\, \value\: $temp, \unit\: \celsius\}插件输出格式约定的是同一行 JSON包含metric、value、unit三个字段。agent 每 30 秒会扫描一次插件目录并执行可执行文件。这个接口让我把机房里几台老设备的 IPMI 数据也统一纳管了。6.3 预留 API 和任务提交的自动化玩法openrig 提供了 REST API基本上面板上能做的操作都能通过 API 完成。我最初看中这一点是因为团队内部有一些自动化流程需要把任务提交接进 CI/CD 管道里。举个例子我们有一个模型评测流程每次代码合并之后自动跑一组评测任务。以前的实现是在 CI 里直接 SSH 到 GPU 机器上跑命令机器多了之后管理起来很麻烦。改用 openrig API 之后CI 只需要向 server 发一个任务提交请求curl -X POST https://openrig.internal/api/v1/tasks \ -H Authorization: Bearer token \ -d { image: eval-image:v1, gpu_count: 1, node: 10.2.3.4, cmd: python run_eval.py --model latest }返回的任务 ID 会写入 CI 的后续步骤等任务完成后CI 通过 API 拉取日志和退出码然后决定是否合并代码。这套流程跑了一个季度稳定得很。如果你有类似需求建议先去看一下 API 文档里关于任务状态码的定义。openrig 的任务状态不是简单的success/failure还包含created、scheduled、running、restarting、isolated等中间态。CI 在判断结果的时候最好把restarting和isolated也考虑进去否则会因为轮询到中间态就提前判定任务失败。最后分享一个我自己的使用习惯。openrig 在这些场景里给我节省了大量重复劳动但它终究不是万能的。我会在每周的维护窗口里轮流用openrig node inspect导出一份所有节点的硬件健康报告哪怕是离线状态的节点也要看看历史数据。监控工具再智能也只是把你从人肉巡检里解放出来最终的判断和决策还是要人来拍板。把工具当成一个靠谱的副驾驶而不是完全自动驾驶这是我和这个项目相处大半年下来最真实的体会。