OpenRig 这个项目,是我被十几台“各自为政”的机器折磨了大半年之后才动手做的东西。所谓 rig,圈子里一般指一套完整的硬件计算平台——GPU 服务器、渲染工作站、测试台架都算;而 OpenRig 要做的,就是把这堆 rig 从“单机孤岛”变成一套开放、可扩展、自己能完全掌控的统一管理体系。它能解决三个最实际的问题:不用再挨台机器登录去看温度,不用再靠人肉记着谁该关机,不用再被商业监控软件的授权费卡脖子。这篇文章写给两类人:一是手里有若干台设备、正为管理工作抓狂的运维和实验室管理员,二是喜欢折腾软硬件结合方案的 DIY 玩家。下面按我实际搭建的过程,从硬件选型到软件部署再到踩坑记录,尽量完整地讲一遍。
1. 项目起源:OpenRig 到底解决什么问题
1.1 先说说那个让人崩溃的场景
我手头这批设备很杂:三台 GPU 训练服务器、两台老工作站、还有几台用来做数据采集的工控机,加起来十几台,分布在同楼不同房间。以前的管理方式是“Excel 台账 + 人肉巡检”,每天上班第一件事是挨个 SSH 上去看温度、看负载,看到哪台风扇狂转就手动 shutdown 清灰。听着不难,但真出问题的时候非常被动:有一次一台机器半夜温度过载,风扇全速转了三个小时,等我早上发现已经积热严重,主板报警灯都亮了。
这种痛点其实很普遍。设备一多,单机层面的“健康状态”就成了黑洞——不知道它什么时候会挂,也不知道挂了多久,更没法判断是偶发还是趋势恶化。我需要一个系统,能持续采集每台机器的温度、功耗、负载,能在异常时主动通知我,最好还能远程开关机。这就是 OpenRig 的第一个原型动机。
1.2 为什么不用现成的商业方案
说实话,市面上现成的机房监控方案不少,我在动手前也评估过。问题集中在几处:商业软件按节点收费,十几台设备一年授权费不低,而且大多绑定自家硬件协议,想接入自制的传感器模块非常费劲;开源监控生态里 Prometheus + Grafana 确实强大,但它的设计偏向“监控指标采集”,对于继电器控制、远程开机、看门狗恢复这类“硬控制”需求支持很弱,需要再单独写一堆胶水代码。
我的诉求很明确:硬件中立、软件开源、部署轻量、能同时管“监测”和“控制”两件事。商业方案绑定太重,通用监控平台又缺控制能力,与其东拼西凑,不如自己做一个兼顾两者的开源框架。OpenRig 就这么立项了,名字也很直白——开放的 rig 管理体系。
1.3 立项时给自己定的几条硬性目标
第一,硬件中立:不限制必须用某品牌的传感器、控制板或智能 PDU,只要能上报标准数据、能接收标准指令就行。第二,部署轻量:管理端用 Docker Compose 一条命令拉起,数据库用默认配置就能跑,小团队和实验室不需要专门运维。第三,可离线:内网环境下完全可用,不依赖云服务。第四,可扩展:后续想接入新的设备类型、新的告警渠道,最好能通过插件方式加进去,而不是改主程序。
这四条看着简单,实际落地时每一步都有坑。后面我会逐个拆开讲。
2. 整体架构与关键技术选型
2.1 三层架构:硬件层、控制层、应用层
OpenRig 的逻辑结构分了三层,跟很多物联网平台的套路类似,但细节上做了不少针对自建机房的调整。
硬件层是每台节点侧的东西:传感器(温湿度、电流、电压)、控制执行器(继电器、智能插座)、以及节点上的一个小 Agent 程序。它负责实实在在的物理数据采集和通断电操作。控制层是管理端服务,运行在一台独立的小主机上,负责接收所有节点的遥测数据、保存历史、判断阈值、下发控制指令,也向前端提供 API。应用层就是用户接触的部分:Web 仪表盘、告警通知(钉钉/企业微信/邮件)、以及对外暴露的 REST API,方便接入自己的运维工具。
这个分层的好处是每层可以独立替换。我实际使用中就换过两次硬件方案,从最初的 Arduino 换成 ESP32,后来又给部分服务器加了 IPMI 通道,但上层管理程序一行没改,因为只要 Agent 上报的数据格式不变,管理端根本不关心下面是什么板子。
2.2 通信协议为什么选 MQTT 加 HTTP 双通道
这是被问得最多的选型问题:为什么不用单一协议?我的答案是“各干各擅长的”。
设备到管理端的遥测数据,比如温度、功耗、心跳,用 MQTT。原因是这类数据量大、频率高(我默认 15 秒一条),MQTT 基于 TCP 长连接,开销小,而且主题订阅机制天然适合多设备上报。每台设备有自己独立的 topic,管理端订阅所有设备,新设备上线也不用改配置,直接按主题规则自动识别。断线重连也是 MQTT 自带的,省了我不少事。
管理端向设备下发控制指令,比如重启、关机、开启某个继电器,用 HTTP 回调。为什么不用 MQTT 下发?因为控制指令需要“确认执行结果”,HTTP 请求-响应的模型天然适合,能拿到明确的成功失败反馈,方便审计。而且指令是低频操作,走 HTTP 的负担完全可以忽略。实际实现时,管理端先把指令写入任务队列,再通过 Agent 暴露的 HTTP 端点下发,Agent 执行完把结果异步回传。双通道各管一边,逻辑清晰很多。
2.3 管理端的软件栈选择
管理端服务我用了 Python 的 FastAPI 框架,配合 SQLite 做默认数据库(部署在单机时够用),也支持切到 PostgreSQL。FastAPI 的异步特性处理设备上报很顺手,而且自带 OpenAPI 文档,调试接口非常方便。前端仪表盘最开始做得很简单,直接是 FastAPI 渲染的 Jinja2 模板加原生 JS,后来引入了 Vue 做了一个单页版,支持实时刷新的设备列表和温度曲线。节点侧 Agent 有两种实现:一个用 Python 写的通用版本,跑在树莓派或者服务器上;另一个是给 ESP32 这类板子写一个精简版固件,只做最基本的温度采集和继电器控制。两侧都通过同一个 MQTT 主题规范和 HTTP 端点规范对接。
图方便,管理端用 Docker Compose 统一编排:一个容器跑 FastAPI,一个容器跑 MQTT Broker(Mosquitto),一个容器跑 Redis 做缓存和任务队列,数据卷挂载宿主机目录存放 SQLite 文件和配置文件。整组服务内存占用控制在 1GB 以内,一个小 NUC 就轻松带起来了。
3. 硬件机组:从零搭建一台“被管理”的节点
3.1 机架结构与散热设计
先说最容易翻车的散热。很多 DIY 玩家把设备塞进密闭机柜就完事,结果夏天温度直接爆表。OpenRig 的节点硬件架构里,散热不是“选个风扇”这么简单,而是要考虑风道走向。我的做法是:机柜底部进风,顶部出风,前门进冷风,后门排热风,中间设备从前向后吹。每组设备之间留至少 2U 的间隔,避免上下叠放互相加热。这个思路参考了标准机房冷热通道的做法,家用环境不需要那么严格,但“前进后出、下进上出”的原则一定要保持。
防尘也建议认真对待。我在机柜进风口装了一层可拆卸的防尘网,每两周拆下来清洗一次。以前不信邪,半年后发现设备散热鳍片积灰严重,温度比新装时候高了 8 度,清理一次花了整个下午。从那以后防尘网就成了标配。
3.2 供电分配与安全保护
供电是整个系统里最不能省钱的环节。我按功率做了简单的预算:三台 GPU 服务器满载大约 1800W、1200W、1200W,两台工作站合计约 600W,工控机忽略不计,总功耗接近 5kW。因此我单独拉了一条 6 平方毫米的供电线路,接了一个 32A 的空气开关,再往下通过 PDU(电源分配单元)分三路输出。每一路 PDU 都带独立的过流保护开关(C16 的空气开关),这样某个节点短路时只会跳这一路,不影响整柜其他设备。
这里强调一个很多人忽略的点:继电器控制 220V 交流电时,必须用带光耦隔离的固态继电器或者接触器,控制端和负载端要彻底隔离,绝不能直接用 GPIO 去控制强电。我用的是 25A 固态继电器,控制信号来自控制板的 3.3V 输出,触发电压通过光耦转换,这样即使控制板异常,强电部分也不会进入控制电路。
3.3 控制板卡与传感器清单
节点控制板我用的是 ESP32 开发板,因为自带 Wi-Fi、ADC 输入、GPIO 和 PWM,完全满足需求,成本也就二三十块钱。每个节点搭配一套传感器:
核心清单大致是:一个 DHT22 温湿度传感器(测环境温湿度)、一到两个 DS18B20 温度探头(贴在 CPU 散热片和机箱出风口)、一个非侵入式电流互感器(接入 PDU 线路测电流)、一个 25A 固态继电器(控制负载电源通断)、加上一个小型风压传感器(测散热风扇是否堵转)。把这些接到 ESP32 上,通过一个简单 PCB 或洞洞板完成连接,每套物料成本控制在 150 元以内。
需要提醒的是,电流互感器是非侵入式的,把主线路穿过它的环即可,不用断电接线,安全性高很多。但互感器输出的是交流电流对应的模拟信号,ESP32 的 ADC 精度一般,采样波动会比较大,我用了多次采样取中位数的办法做滤波,效果可以接受。如果要做精确的功耗计量,更推荐直接买支持 Modbus 的功率计模块,走 RS485 接入控制板,精度和稳定性都比互感器方案好,代价是成本高一些。
4. 软件实现:设备接入、监控与自动化控制
4.1 设备注册与心跳机制
设备上线第一步是注册。我设计的流程是:节点 Agent 启动后,先向 MQTT 主题openrig/register发布一条 JSON 注册消息,包含设备型号、固件版本、MAC 地址、自报一个设备名。管理端收到后检查 MAC 是否在数据库里,如果没有则自动创建设备记录并分配一个正式 ID;如果已经存在,就更新状态为在线并下发最新配置。这里有个小设计:注册消息不需要手工配置管理端地址,因为 MQTT Broker 的地址已经写死在 Agent 配置文件里了,设备只需知道 broker 在哪,不用知道管理端是谁。
心跳机制是所有在线判断的基础。每台设备以 15 秒为周期向自己的主题openrig/devices/{id}/heartbeat发布一条心跳消息,包含当前时间和累计运行秒数。管理端收到后更新设备的上次心跳时间。判断离线的规则是“三倍心跳周期内没有收到任何消息”,也就是 45 秒。之所以设三倍而不是两倍,是为了容忍 MQTT 偶发的网络抖动和 broker 重连造成的短暂延迟,减少误报。
4.2 监控指标设计:电压、温度、功耗、负载
每台设备周期性上报的遥测数据,格式统一为 JSON:
{ "device_id": "dev_gpu_01", "ts": 1718000000, "temp_c": {"cpu": 62, "board": 41, "exhaust": 38}, "humidity": 42.5, "current_a": 3.2, "voltage_v": 233.1, "power_w": 745.9, "fan_rpm": 3200, "load_pct": 78 }数据存储采用“最新值 + 历史曲线”的策略:最新值直接存在 Redis 中,仪表盘读取只耗时零点几毫秒;历史数据写入 SQLite,按设备 ID 和时间戳建索引。为了防止数据膨胀,我在管理端设置了默认保留 30 天的策略,超过的由定时任务自动清理。如果后续设备量上到几十上百台,建议把存储换成时序数据库(比如 InfluxDB),查询和压缩性能会好很多。
阈值判断放在管理端做,统一配置而不是分散到各设备。好处是改阈值不用逐个刷设备固件,而且可以做跨设备联动。比如我配置了“机房环境温度超过 35°C 就自动降低 GPU 负载”,这类联动逻辑如果放在设备端反而麻烦。
4.3 远程电源控制与看门狗自动恢复
远程开关机是 OpenRig 最受欢迎的功能。实现上有三种途径,可以混合使用:一是通过 ESP32 控制固态继电器,直接为 220V 交流输入通断电,这是最通用的办法,任何机器都适用;二是通过网络唤醒(Wake-on-LAN),适用于支持 WOL 的设备,优点是不用断电,但需要主板 BIOS 开启 WOL 功能;三是使用服务器自带的 IPMI/Redfish 协议,管理口直接发指令做优雅关机或重启,这是最“原生”的方式。
我实际使用中把三者都接进来了,管理端的控制面板上每个节点有一个“电源操作”下拉菜单,根据设备类型选择可用的方式。例如有 IPMI 的服务器优先走 IPMI,工作站走继电器断电重启,支持 WOL 的机器用 WOL 开机 + 脚本软关机。在实现时我给每种方式封装成独立的执行器模块,通过统一接口注册到控制服务里,加新方式只需写一个执行器即可。
看门狗恢复是另一个让大家觉得“省心”的功能。逻辑是:管理端监控每个节点的遥测,如果发现 CPU 温度连续 5 分钟超过 85°C,且没有人工干预,就自动执行预设的恢复策略——通常是先发告警,5 分钟后自动执行优雅关机,再等待 3 分钟重新开机。这个功能一定要配置“确认”机制,我设了连续 5 个采样周期都超阈值才触发,避免单次毛刺造成误重启。
4.4 告警通知与数据可视化
告警分三个等级:警告(温度高于 70°C、负载长期 90% 以上)、严重(温度高于 80°C、电流异常波动)、致命(温度高于 90°C、设备离线超过 15 分钟)。不同等级走不同的通知渠道:警告只记录到事件日志并推送到企业微信;严重推送到钉钉群并同时发邮件;致命级除了推送,还会触发看门狗自动策略。
告警去重在实现上很关键,不然会疯狂轰炸。我用的是“状态切换”模式:只有当状态从正常变为异常时才发送告警,后续持续异常不再重复发;直到状态恢复为正常时发一条恢复通知。配合这种模式,我还给每条规则设置了静默时间,例如同一设备同一条规则 30 分钟内最多推送一次,避免边缘抖动导致刷屏。
可视化方面,我一开始用的是管理端自带的简单仪表盘,展示每台设备的温度曲线和状态灯。后来把遥测数据同时转发了一份到 Prometheus(翻译成标准的 push 格式),接上 Grafana 做机房总览大屏,效果立刻提升了一个档次。不过这个属于锦上添花,没有 Grafana 也能正常运行。
5. 实战部署:半小时拉起一套 OpenRig 管理端
5.1 环境准备与一键部署
部署环境很简单,一台 Linux 主机即可,建议 2 核 4GB 内存起步,我实际用的是 Intel NUC,装了 Debian 系统。需要提前安装 Docker 和 Docker Compose 插件。
部署时直接使用仓库里的docker-compose.yml,核心服务定义如下:
services: mqtt: image: eclipse-mosquitto:2 ports: - "1883:1883" volumes: - ./mosquitto/config:/mosquitto/config - ./mosquitto/data:/mosquitto/data redis: image: redis:7-alpine volumes: - ./redis-data:/data server: build: ./server ports: - "8000:8000" depends_on: - mqtt - redis environment: - MQTT_HOST=mqtt - MQTT_PORT=1883 - REDIS_HOST=redis volumes: - ./data:/app/data在仓库根目录执行docker compose up -d,稍等两分钟服务就起来了。首次启动会自动执行数据库初始化,并创建一个默认管理员账号(初始化密码在启动日志里)。我建议上来先把默认密码改掉,别跟我一样图省事留着,后来测试设备接入时发现有人摸到了管理端口,虽然没造成破坏,但吓出一身冷汗。
5.2 添加第一台设备的完整流程
在 Web 仪表盘里找到“设备管理”,点击“添加设备”,录入基本信息:设备名、MAC 地址(注册时会自动识别,但先填上方便对照)、物理位置、用途说明、负责联系人。保存后,系统会生成一个设备 ID 和一个预共享令牌(token)。这个令牌要写进节点侧 Agent 的配置文件里,作为设备与管理端之间的鉴权凭证。
接着去节点侧安装 Agent。以通用 Python Agent 为例,先在设备上克隆 Agent 仓库,复制.env.example为.env,填上三项关键配置:管理端 MQTT Broker 的 IP 端口、设备 ID、token。然后启动 Agent 服务:
pip install -r requirements.txt python agent.py start --config .env启动后观察日志,如果看到 “register ok” 和第一条心跳上报的消息,说明接入成功了。回到管理端页面刷新,设备状态会从“未连接”变成“在线”,温度、功耗等指标开始滚动。整个过程第一次操作大约需要 15 分钟,后面熟悉了 5 分钟就能加一台。
5.3 配置告警规则和联动策略
告警规则配置在“策略中心”页面,以 JSON 形式编辑,模块也支持可视化表单。以“GPU 服务器高温告警”为例,规则如下:
{ "name": "gpu_high_temp", "scopes": ["dev_gpu_01", "dev_gpu_02"], "condition": "temp_c.cpu >= 80 and duration_min >= 3", "level": "serious", "actions": ["notify:wecom", "watchdog:soft_shutdown"], "silence_min": 30 }这里的duration_min表示连续满足条件 3 分钟才触发,watchdog:soft_shutdown定义了温度持续超标的自动关停策略。我建议第一周先只配置“通知”类动作,把阈值调教得正常了再加“自动执行”类动作,避免误触发把正在跑任务的服务给停了。
5.4 联调验证清单
配置完成后,按照下面这份清单逐项验证,避免漏掉关键环节:
| 检查项 | 预期结果 | 验证方式 |
|---|---|---|
| 设备上线 | 页面状态从“未连接”变“在线” | 刷新设备列表 |
| 遥测上报 | 温度/功耗每 15 秒刷新一次 | 查看设备详情页 |
| 心跳离线判断 | 关闭 Agent 后约 45 秒显示离线 | 手动停止 Agent 进程 |
| 告警通知 | 触发规则后指定渠道收到消息 | 用热风枪吹传感器模拟超温 |
| 远程重启 | 继电器通断后设备重新上电 | 在控制面板执行重启 |
| WOL 开机 | 关机后能远程唤醒 | 执行 WOL 指令并观察 |
这份清单是我实际联调时反复使用的模板,建议按自己的设备情况增删。其中“用热风枪吹传感器模拟超温”这一招非常实用,能快速测试整个告警链路是否打通,不用真的等设备过热。
6. 常见问题与排查技巧实录
6.1 设备反复掉线,心跳丢失
现象是设备在管理端一会儿在线一会儿离线,频率不定。排查时我先看 MQTT Broker 的日志,发现设备断连重连的循环记录。进一步分析原因:设备离管理端所在房间隔了一面承重墙,2.4G Wi-Fi 信号强度只有 50%,不稳定。解决方法是给设备侧加了一个 5G 频段的 Wi-Fi 模块,或者干脆用有线网连接 ESP32 的以太网扩展,稳定之后掉线问题彻底消失。
还有一种情况是在大流量的局域网里,路由器对连接数有限制,导致 MQTT 长连接被踢掉。排查手段是检查路由器连接数监控,必要时把管理端换到独立子网,或者调整设备的心跳周期从 15 秒改成 30 秒,降低连接的保活频率。
6.2 温度读数漂移的秘密
DS18B20 这类数字温度传感器标称精度不错,但实际安装位置不同,读数差异很大。我遇到过两个节点同样显示 60°C,实际手感一个明显更烫。原因出在安装方式:一个探头直接贴到了散热片上,另一个在空中悬着,测的是环境温度。解决办法是统一探头安装规范——贴在散热片上的用导热胶固定,并包裹隔热海绵避免周围气流干扰;测环境温度的则远离风扇出风口。另外,传感器的 ADC 采样会有漂移,我加了滑动平均滤波,窗口取 5 个采样点,读数稳定后基本不抖。
6.3 远程开机失败的几个坑
远程开机失败是最容易让人一头雾水的问题。先排软件层:确认 WOL 功能是否在主板 BIOS 中开启(很多主板默认关闭),确认管理端发送 WOL 包的网络跟设备在同一个广播域(跨路由通常要指定广播地址),确认设备的网卡在关机状态下仍然通电待机。我踩过的一次坑是:设备关机后系统把网卡完全断电了,WOL 包到了网络口但网卡根本没工作,自然无法唤醒。这种只能改成继电器断电重启方案。
继电器方案也要注意触点选择:固态继电器分常开和常闭型号,常开的断电时负载断开,常闭的断电时负载仍然导通。我用的是常开型,逻辑是“控制端给信号才导通”,这样控制板异常时设备保持断电状态,起码不会出现想关机关不掉的情况。
6.4 告警风暴和误报的处理
告警风暴发生在网络瞬断的时候:设备全部掉线,管理端一次性为十几台设备触发“致命离线”告警,钉钉群被刷了 60 多条消息。后来我在离线告警规则里加了一个“影响范围”判断:如果检测到超过半数设备同时离线,则判定为网络或管理端自身故障,只发送一条综合告警,不逐台发。这个逻辑非常实用,强烈建议抄走。
误报的另一个来源是阈值设置太激进。我一开始把温度告警阈值压在 75°C,结果夏季午后机房气温一高,偶尔一台设备瞬时跳到 76°C 就告警,而实际负载不高,运行完全正常。后来我引入了“持续时间”条件(连续 N 分钟超阈才告警),误报率立刻降了九成。
6.5 几条独家避坑经验
最后整理几条零碎但很重要的经验。第一,控制板的电源一定不能跟被控制的设备共用同一路 PDU,否则你通过继电器把设备断电后,控制板自己也断电了,远程开机就成了笑话。我给每块控制板单独接了一路 5V 的直流电源(用独立的小适配器),保证它在设备断电时仍然存活。第二,MQTT 的 QoS 建议全部使用 QoS 1,QoS 0 在网络抖动时可能丢消息导致误判离线,QoS 2 在这个场景下没有必要,性能反而白白受影响。第三,所有 Agent 和 Broker 之间的通信在生产环境务必加 TLS,虽然内网环境看起来安全,但我就遇到过同一网段里其他设备的记本误连到 Broker 导致数据串了的奇怪现象。第四,管理端数据库一定要定时备份,我配置了每天凌晨两点用 cron 把 SQLite 文件压缩后传到另外一台备份机,半年下来用过两次恢复,每次都救了急。
OpenRig 这个项目做到现在,最大的感触是:所谓“管理”,不是把所有设备塞进一个平台就完事,而是要在监测、控制和自动化之间找到适合自己场景的平衡。我最初迷信“全自动”,后来发现有的事情半自动反而更安心——比如自动关机策略,我留了确认窗口而不是当场执行。如果你也在维护多台设备,建议从最小闭环开始:先把遥测和告警跑起来,再逐步加控制能力。等真正跑稳了,你会发现自己对机房状态的感知,从“三天一看”变成了“随时清楚”,这种确定性,就是最实在的回报。