OpenRig:开源多设备远程监控与电源管理实战指南 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 BrokerMosquitto一个容器跑 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_HOSTmqtt - MQTT_PORT1883 - REDIS_HOSTredis 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 1QoS 0 在网络抖动时可能丢消息导致误判离线QoS 2 在这个场景下没有必要性能反而白白受影响。第三所有 Agent 和 Broker 之间的通信在生产环境务必加 TLS虽然内网环境看起来安全但我就遇到过同一网段里其他设备的记本误连到 Broker 导致数据串了的奇怪现象。第四管理端数据库一定要定时备份我配置了每天凌晨两点用 cron 把 SQLite 文件压缩后传到另外一台备份机半年下来用过两次恢复每次都救了急。OpenRig 这个项目做到现在最大的感触是所谓“管理”不是把所有设备塞进一个平台就完事而是要在监测、控制和自动化之间找到适合自己场景的平衡。我最初迷信“全自动”后来发现有的事情半自动反而更安心——比如自动关机策略我留了确认窗口而不是当场执行。如果你也在维护多台设备建议从最小闭环开始先把遥测和告警跑起来再逐步加控制能力。等真正跑稳了你会发现自己对机房状态的感知从“三天一看”变成了“随时清楚”这种确定性就是最实在的回报。