如果你管理过超过三台显卡机器,就一定体会过那种被“远程运维”支配的疲惫:登录每台机器看一眼功耗、温度,跑一圈脚本检查负载,再手动重启僵死的进程。尤其在机器分散在不同机房、甚至不同城市时,这种巡检效率低得令人抓狂。
openrig 就是为解决这类场景而生的开源项目。它是一套轻量级的自托管设备管理平台,核心思路很朴素:在被管机器上装一个 Agent,通过它采集硬件状态、接收远程命令,把所有机器的状态汇总到一个控制台里统一查看和管理。它不依赖任何云服务,数据全部留在你自己的服务器上,适合个人开发者、小型计算集群、以及所有想摆脱商业订阅费和平台绑定的运维玩家。这篇内容就围绕 openrig 的架构思路、部署步骤、核心功能展开,并把我在实际使用中踩过的坑一并分享出来。
1. 项目概述与整体设计思路
1.1 openrig 到底解决了什么痛点
先说场景。过去我管理过一批显卡设备,每台机器上跑着不同类型的计算任务。刚开始数量少,直接 SSH 登录操作还能应付,可一旦过了五台,问题就完全不同了。
最直观的三个痛点:一是状态获取慢,想知道每台机器的 GPU 温度、功耗、负载,至少要打开五六个终端窗口,或者写一堆自动化脚本轮询;二是故障响应被动,机器死机、显卡掉驱动、温度过热,通常都是任务失败之后才发现,此时损失已经造成;三是操作不统一,有的机器要用 screen 挂任务、有的要改配置文件、有的要重启服务,脚本和命令散落各处,很难维护。
openrig 把这些问题收敛成两个核心模块:Agent 负责采集和命令执行,Server 负责汇总和展示。从运维视角看,它就做了一件事——把每台机器的“状态面板”和“远程操作入口”集中到一个 Web 控制台。听起来不复杂,但对于像我这种规模不大、又不想引入整套商业监控系统的人来说,它恰好长在了需求点上。
1.2 架构选型背后的取舍
openrig 采用了经典的 Agent-Server 架构,这也是同类项目最常见的选型。为什么不用纯推送式的采集方案?因为被管机器的 IP 经常变化,尤其是在 NAT 网络环境下,服务端主动拉取数据几乎不可行。Agent 主动向 Server 发起连接,把状态数据推上来,这是最省事也最稳定的反向通信模式。
通信协议上,Agent 与 Server 之间走的是 WebSocket 长连接,数据格式是 JSON。选 WebSocket 而不是 HTTP 轮询,原因很实际:HTTP 轮询要反复建立连接,高频采集时开销大,而且难以实现服务端实时下发命令。WebSocket 是全双工通道,Agent 的状态可以每秒或每几秒推一次,服务端也能随时把指令推给 Agent,双向实时性都能保证。
数据存储方面,openrig 默认使用 SQLite 而不是 MySQL 或 PostgreSQL。这一点我最初有些怀疑,怕高并发下撑不住,后来想想这个项目的定位:管理几十台机器,每台几秒上报一次,这个写入量对 SQLite 来说完全没问题,还省去了维护独立数据库的麻烦。整套部署下来就一个二进制或一个容器,这恰恰是轻量级工具该有的样子。
对比几款商业产品,Hive OS 这类平台在功能和生态上确实更完善,但对硬件有倾向性限制,账户体系也在云端,数据不掌握在自己手里,长期使用还涉及订阅费用。openrig 的价值不是功能碾压,而是提供了一条自托管、可改造、不折腾的路。它给了你一个完整的框架,剩下的自动化逻辑、告警规则、甚至前端展示都能按自己的需求改。
2. 环境准备与部署实操
2.1 部署前需要准备的软硬件
openrig 对硬件的要求相当克制。Server 端可以用一台树莓派 4B、一台老旧的 x86 小主机,或者直接和我一样扔在一台 2C4G 的云服务器上。主要负责接收数据、落库、提供 Web 界面,没有任何重负载计算,不需要 GPU。
被管机器这边的情况稍微复杂一点,需要系统能正常访问到 GPU 设备。如果是 NVIDIA 显卡,系统里要有 nvidia-smi 或至少能通过 /proc/driver/nvidia 读取基础信息;AMD 显卡则需要系统支持 rocm-smi。系统本身建议使用较新的 Linux 发行版,Ubuntu 20.04/22.04、Debian 11/12 都验证过,Windows 下的支持要弱很多,不建议在生产环境尝试。
网络方面可以这样规划:Server 上开放一个固定端口,被管机器只要能访问到这个端口就行。最简单的方式是让 Server 拥有一台公网 IP 的机器,或者用内网穿透工具把端口暴露出去。Agent 与 Server 之间只走这一个端口,所以防火墙规则也很好写。
以下是推荐配置表格(基于常见实践整理):
| 角色 | 最低配置 | 推荐配置 | 依赖项 |
|---|---|---|---|
| Server | 1C1G / 10GB 磁盘 | 2C4G / 20GB SSD | Docker 或 Node.js 18+ |
| Agent(被管机器) | 无特殊要求 | 与计算任务本身匹配 | Linux 系统、GPU 驱动工具 |
| 网络 | Server 可被 Agent 访问 | 同一内网或公网互通 | 端口 443 或自定义端口 |
2.2 Docker Compose 一键部署与手动配置
official 仓库提供了一键部署脚本,但我个人更推荐用 Docker Compose 跑 Server 端,后续升级和回滚都方便。我已经在自己的服务器上维护了一套 compose 配置,结构如下:
version: "3.8" services: openrig-server: image: openrig/server:latest container_name: openrig-server restart: unless-stopped ports: - "8080:8080" environment: - OPENRIG_DB_PATH=/data/openrig.db - OPENRIG_AGENT_PORT=8080 - OPENRIG_JWT_SECRET=change_this_to_a_long_random_string - OPENRIG_REGISTER_TOKEN=my_register_token volumes: - ./data:/data几个环境变量必须说明一下:
OPENRIG_DB_PATH指定数据库文件位置,建议挂载到持久化卷里,服务器重装不丢数据。OPENRIG_REGISTER_TOKEN是 Agent 注册时用的预共享令牌,相当于临时入场券,Agent 拿着它首次注册后,系统会分配真正的设备 ID 和密钥,之后这个 token 就不再需要了。OPENRIG_JWT_SECRET用于签发登录态的 JWT,务必改成足够长的随机字符串,不要用默认值。
启动命令很简单:
docker compose up -d首次启动后,浏览器访问http://你的服务器IP:8080,如果看到登录页面,说明服务端已经跑起来了。默认管理员账号和密码会输出在容器日志里(初始是一个随机生成的密码),第一次登录后要立刻改掉。
如果你不想用 Docker,也可以拉源码手动跑。后端是 Node.js 项目,前端打包后由后端直接托管静态文件,因此只需要起一个进程即可:
git clone https://github.com/openrig/openrig.git cd openrig/server npm install npm run build # 构建前端静态资源 OPENRIG_DB_PATH=./openrig.db OPENRIG_JWT_SECRET=your_secret node src/index.js这个部署方式的灵活度更高,比如可以把前端静态文件单独用 Nginx 托管、后端进程交给 systemd 守护,适合想深度定制的人。
2.3 添加第一台被管机器:Agent 安装与注册
Server 端就绪后,接下来是把第一台机器纳管进来。在目标机器上安装 Agent 同样很简单。openrig 提供了单个二进制的 Agent,解压即用,不依赖 Python 运行时和一堆第三方库,这个设计让我很舒服——被管机器本来就是跑计算任务的,越少侵入越好。
# 下载对应架构的 Agent(以 linux-amd64 为例) wget https://github.com/openrig/openrig/releases/download/v0.4.2/openrig-agent-linux-amd64 # 赋予执行权限 chmod +x openrig-agent-linux-amd64 # 注册并启动 ./openrig-agent-linux-amd64 \ --server wss://your.server.com:8080 \ --register-token my_register_token \ --device-name node01注册过程中的流程值得注意。Agent 启动后先带着 register-token 和 device-name 请求 Server,Server 校验 token 合法后,会生成一个新的 Agent 专用密钥并返回。Agent 把这份密钥保存在本地配置文件中(默认在/etc/openrig/agent.json),之后每次重连都用这个专用密钥做鉴权,不再需要 register-token。
这个设计比直接保存 register-token 安全得多,因为注册令牌可以被回收或更换,每一次注册分发一个小范围的设备密钥也便于管理:哪天某台机器要转交给别人,直接在控制台吊销设备密钥即可,不必全局换 token。
一次性注册多台机器时,不用一台台手动输入命令,可以配合 Ansible 或你自己的初始化脚本批量下发。我习惯把 Agent 的安装包和启动命令写进装机脚本里,新机器出厂就能自动接入 openrig,省去大量人工操作。
3. 监控、远程管理与告警配置
3.1 状态数据的采集逻辑与刷新策略
openrig 的监控能力核心在 Agent 的数据采集模块。Agent 每间隔一段可配置的时间(我习惯设为 3 秒),会执行一组采集动作,把所有硬件状态聚合成一个 JSON 包,通过 WebSocket 推送到 Server。
以 NVIDIA 显卡为例,采集主要依赖 nvidia-smi 的输出。它需要解析的内容包括显卡名称、驱动版本、核心温度、显存使用率、功耗、风扇转速、及当前运行进程。这些信息足以判断一张显卡是否处于健康状态。
CPU 和内存数据则通过读取/proc/stat、/proc/meminfo实现,对于国产化系统、容器环境同样有效。加上了磁盘 I/O 和网络吞吐统计后,这组数据已经能覆盖常规运维 90% 的需求。
刷新间隔的取舍有一点讲究。采集太频繁,Agent 自身会消耗少量 CPU 资源,对被管机器上的计算任务产生干扰;间隔太长,页面上的监控曲线又不连续,故障发生时看不到拐点。从我实测来看,3 秒一次对 GPU 状态监控足够,温度变化本身是缓慢过程,不需要毫秒级数据;而 CPU 负载曲线在 5 秒粒度下也能清晰地反映波动规律。
下面是采集数据的 JSON 示例,方便二次开发时参考:
{ "device": "node01", "timestamp": 1700000000, "host": { "cpu_usage": 12.5, "mem_usage": 46.2, "disk_read": 1024, "disk_write": 2048, "net_rx": 31200, "net_tx": 8900 }, "gpus": [ { "index": 0, "name": "NVIDIA GeForce RTX 3090", "temperature": 68, "power": 310, "utilization": 98, "mem_used": 21300, "mem_total": 24576, "fan_speed": 80 } ] }3.2 远程命令与自动化任务的配置
监控是基础,真正提升效率的是远程命令功能。openrig 允许在控制台上预设若干命令模板,然后对一台或多台设备批量下发。
这里必须强调安全边界:Agent 端默认不会执行任意命令,而是只允许执行 Server 推送下来的、并能在本地白名单中匹配到的命令。这个白名单是 Agent 配置文件的allowed_commands字段,属于“双重校验”机制。即便控制台账号被盗,攻击者也无法通过控制台在被管机器上执行白名单之外的操作。
我的白名单配置通常长这样:
{ "allowed_commands": [ "systemctl restart openrig-agent", "systemctl restart monitor", "nvidia-smi --reset-gpu", "bash /opt/scripts/relaunch_task.sh", "uptime" ] }在控制台上创建命令时,可以为每条命令设置一个显示名称和参数说明。例如,bash /opt/scripts/relaunch_task.sh可以命名为“重启任务”,并添加选择参数(如任务 ID),但参数校验逻辑预处理后才会下发给 Agent。
执行超时也是必须考虑的问题。某些命令(比如 GPU 驱动重置)可能需要 10 秒甚至更久,openrig 默认的超时时间相对保守,如果命令总是被判定超时,可以调大单个命令的超时时间。要注意的是,超时后会终止命令进程,并返回截至超时前收集到的输出片段,该输出会完整保留在任务记录里,方便排查。
3.3 告警通知:把被动等待变成主动响应
告警功能是 openrig 的另一个核心能力。它支持自定义条件规则,基础规则包括 CPU 温度超过阈值、内存剩余不足、某块 GPU 温度过高、GPU 进程崩溃,也可以基于 Agent 心跳丢失事件触发离线告警。
触发后 actions 可以设置为 Webhook 通知或者执行服务端脚本。Webhook 是最常用的方式,把消息 POST 到钉钉自定义机器人、企业微信机器人、或者你的 IM 工具地址即可。配置方式非常简单,在控制台添加一条规则,设定阈值,填入 Webhook 地址。
我的常用规则模板供参考:
| 规则名称 | 条件 | 动作 | 说明 |
|---|---|---|---|
| GPU 高温 | GPU 温度 >= 85℃ | Webhook(dingtalk) | 连续两次触发才告警,防止瞬时波动打扰 |
| GPU 掉卡 | GPU 数量 < 预期数量 | Webhook+远程命令 | 掉卡立即告警,并尝试执行重置命令 |
| 主机失联 | Agent 心跳超时 2 分钟 | Webhook(dingtalk) | 提醒人工介入 |
| 磁盘不足 | 磁盘剩余空间 < 10% | Webhook | 提前预警,防止日志写满 |
规则里很实用的一个配置是“连续 N 次满足条件才触发”。温度瞬时冲高又回落很常见,如果每次波动都告警,你会在半小时内收到几十条消息,真正的异常反而被淹没。我通常把阈值设置为超过 85℃ 并持续 2 个采集周期再触发告警,既不会漏报,也不会频繁打扰。
4. 常见问题与排查技巧实录
4.1 Agent 永远显示离线
这是使用频率最高的问题。优先检查三件事:网络连通性、注册密钥、防火墙规则。
网络连通性可以这样验证:在被管机器上手动执行curl https://your.server.com:8080/api/health,如果无法返回 JSON 或者连接卡住,说明 Agent 根本到不了 Server。
接着看 Agent 日志。日志通常打印在 stderr 或/var/log/openrig-agent.log。若出现 401/403 错误,说明设备密钥不匹配,可以重新生成密钥或在/etc/openrig/agent.json里手动替换。
还有一个坑容易被忽略:注册时的--server参数写成了 ws://(明文 WebSocket),而 Server 只启用了 wss://(加密 WebSocket),握手失败导致离线。要是你的 Server 通过 Nginx 反向代理,注意在代理配置中开启Upgrade和Connection头,否则也可能出现频繁断连。
4.2 温度或功耗数据读取不到
这类问题多半出在被管机器的环境上。NVIDIA 显卡需要驱动正常安装,nvidia-smi能正常输出。很多人在最小化安装系统后没装 NVIDIA 驱动,nvidia-smi提示 command not found,openrig 自然拿不到显卡数据。
在虚拟机里透传了 GPU 的情况下,驱动可能能识别,但温度传感器无法从 hypervisor 层正确读出,显示 0 或异常值。这属于虚拟化限制,不是 openrig 的缺陷。建议优先在物理机或裸金属环境部署,以保证数据准确性。如果只追求任务能跑、不关心传感器数据,可以把该 GPU 的采集项从配置中剔除,避免告警规则误判。
4.3 SQLite 数据库不断膨胀
运行几个月后,数据库文件可能出现明显增长。原因通常是历史监控数据表积累了过多的原始采样记录。3 秒一个点,一台设备一天就产生近三万条记录,几十台设备积累下来数据量确实可观。
openrig 内置了数据保留策略,可以在控制台设置保留天数。但如果你是自己手动部署的,需要确认后台是否有定时清理任务。没有的话,可以自己写一个 cron 脚本:
# 清理 7 天前的历史数据 0 3 * * * sqlite3 /data/openrig.db "DELETE FROM metrics WHERE timestamp < strftime('%s', 'now', '-7 days');"执行完可以用VACUUM命令回收磁盘空间。如果保留大量历史数据是刚需,那还是建议拆库到 MySQL,并对表按日期做分区。
4.4 WebSocket 频繁断连与重连风暴
这个现象多发生在网络质量不稳定或机器长时间睡眠后恢复的场景。openrig Agent 内置了指数退避重连机制,默认退避上限是 60 秒,偶尔断线重连不会有问题。
真正的问题是,当一台服务器上有大量 Agent 同时断线再同时重连,会在服务端形成瞬时连接风暴。假如你有 30 台设备掉线恢复,30 个 Agent 在同一时刻涌入,Server 端还没来得及逐一握手,部分连接又超时了,于是再次发起重连……这就是经典的重连风暴模式。
解决方法是引入“抖动”。在 Agent 的配置文件中,把重连初始延迟设置为一个随机区间,比如 1-5 秒。即使所有 Agent 同时掉线,它们重连的时间点也会被摊开,Server 端的连接压力会小很多。这个参数在大型集群中的效果非常明显。
4.5 远程命令不生效
命令不生效的原因通常有两种。第一,白名单里只写了命令主体,但实际下发时带上了参数,例如白名单是systemctl restart monitor,你下发的是systemctl restart monitor --force,压根匹配不上。匹配逻辑默认要求完整命令完全一致,不带参数的匹配模式需要额外开启。
第二,Agent 进程没有权限执行该命令。openrig Agent 默认以普通用户运行,如果你在配置中允许了systemctl restart xxx这类特权操作,需要为 Agent 配置 sudo 免密规则,并且确保 Agent 的命令执行上下文能够继承正确的环境变量。更稳妥的替代方案是为特定脚本设置sudoers权限:
openrig ALL=(root) NOPASSWD: /opt/scripts/relaunch_task.sh这样 Agent 能执行特定脚本,其他特权操作依然禁止。
5. 二次开发与扩展思路
如果部署使用只是第一步,那么二次开发决定了这个项目在你手里的上限。openrig 的 API 层全部基于 RESTful + WebSocket,接口风格干净,文档也全,适合在此基础上对接自己的运维系统。
比如,我想实现“GPU 温度过高时自动暂停低优先级任务”。这需要拿到温度数据后再编排命令。openrig 的 WebSocket 接口支持订阅实时数据流,简单写一个 Python 脚本就能实现:
import asyncio, json, websockets async def watch_gpu(): async with websockets.connect("ws://your.server.com:8080/ws/stream?device=node01") as ws: async for raw in ws: data = json.loads(raw) for gpu in data.get("gpus", []): if gpu["temperature"] > 85: print("高温警报,执行低优先级任务暂停") # 这里调用 openrig 的远程命令接口 await ws.send(json.dumps({ "type": "execute_command", "command": "bash /opt/scripts/pause_low_prio.sh" })) asyncio.run(watch_gpu())这段脚本的思路是:订阅指定设备的数据流,持续判断 GPU 温度,一旦超过阈值就通过 WebSocket 下发暂停命令。实际应用时可以加上冷却时间控制,避免脚本反复触发。
前端方面也预留了扩展点。控制台页面里的数据看板采用卡片式布局,每一个卡片对应一项指标,你可以很方便地新增自定义指标卡片,把 Agent 数据里包含的新增字段展示出来。配合 Grafana 用也完全可行,只需要把 openrig 的 API 接入到 Prometheus exporter 做数据透传。
6. 安全性配置注意事项
自托管系统的安全责任全在自己身上。我强烈建议在生产环境启用 HTTPS 连接,至少不要在裸奔的公网 IP 上跑明文 WebSocket。最简单的方式是用 Caddy 或 Nginx 做一层反向代理,自动签发证书。
# Caddyfile 示例 your.server.com { reverse_proxy :8080 }Caddy 会自动申请 Let's Encrypt 证书,Agent 连接时用wss://your.server.com即可。配置完成后,我顺手做了一次安全自查,重点看三个点:默认管理员密码是否修改、register-token 是否已经失效或更换、设备密钥是否只分发给受信 Agent。整体靠系统自身的 token 机制闭环,没有额外的账户体系依赖,安全性比单纯的 HTTP 裸奔透明很多。
另外,服务端数据库文件要定期备份。/data/openrig.db是整个系统的核心,一台机器更换后重新注册容易,但历史监控数据和告警记录丢了就找不回来。我写了一个简单的 cron 脚本,每天凌晨把数据库文件复制到远程备份目录,保留 30 天,基本能做到随时随地恢复。
7. 最后的几点体会
这套系统我实际跑了差不多半年,最大的感受就是设备管理这个事情的复杂度不在于单点功能多强,而在于所有信息能不能在一个入口里持续地自然流转。openrig 的价值也正在于此——它把所有被管机器的状态、命令入口、告警事件统一到一个界面里,省掉的全是重复琐碎的 SSH 操作。
如果说有什么建议,我会说:不要一上来就追求把所有功能一次性配置好,先从“接入一台机器、设置一条温度告警、建一个重启命令”开始。等流程跑顺了,再逐步把手头的机器都纳管进来,把常见故障处理沉淀成固定的命令或脚本。这样积累出来的运维体系,比任何商业工具都更贴合你自己的使用习惯。
openrig 的社区还处于早期阶段,文档和生态也在持续完善,但它的核心框架和 API 已经足够稳定。把它当成一块基础积木,结合自己的需求做延伸,才是这个开源项目最大的乐趣所在。