02-NetBox多站点发现实战:Orb + Diode + Python 脚本联动落地
- 这篇文章聚焦多站点发现链路,核心是把 Orb Agent -> Diode -> NetBox 这一段稳定跑通。 - 内容不仅覆盖 CentOS 7 上的安装与连通问题,也解释了为什么“发现成功”并不等于“资产模型完整”。 - 它适合放在部署篇之后阅读,作为后续 IP 纳管和设备建模。

摘要
- 这篇文章聚焦多站点发现链路,核心是把
Orb Agent -> Diode -> NetBox这一段稳定跑通。 - 内容不仅覆盖 CentOS 7 上的安装与连通问题,也解释了为什么“发现成功”并不等于“资产模型完整”。
- 它适合放在部署篇之后阅读,作为后续 IP 纳管和设备建模的前置环节。
最近我在做 NetBox 多站点资产自动发现的实践案例。
前面的站点其实都已经差不多打通了,最后剩下一个站点,环境偏老,是一台 CentOS 7 服务器。原本我以为就是按流程补一下 Docker、起一下 Orb Agent、扫一遍网段就完事,结果真正上手后发现,这个站点反而是最容易踩坑的一个。
因为它的问题不是单点问题,而是几个问题叠在一起:
- CentOS 7 已经比较老了,Docker 安装并不丝滑
- Orb Agent 容器能起来,不代表真的在扫描
- Diode 认证参数写法不对,表面没报错,实际就是不工作
- 扫描结果进了 NetBox 以后,还得继续补设备、接口、链路,不然资产模型还是不完整
- 后面 4 个 Python 自动化脚本还依赖
easysnmp,而这个包在 CentOS 7 上安装又很容易翻车
这篇文章,我就把我这次从头到尾的实战过程,按一个完整闭环复盘出来。不是讲概念,而是讲我在现场是怎么一步一步把它跑通的。
一、我这次做的到底是什么架构
整体架构
我这次的目标不是每个站点自己部署一套 NetBox,而是做一个 主站点统一纳管、分站点执行发现 的架构。
整体思路很简单:
- 主站点:部署 NetBox 和 Diode
- 分站点:只部署 Orb Agent
- Orb Agent 在分站点本地扫描网段
- 扫描结果通过 Diode 回传到主站点
- 主站点 NetBox 统一接收结果
- 然后我再通过自动化脚本,把这些 IP 进一步补成设备、接口、链路
也就是说,Orb 不负责把 NetBox 资产模型一次性全补齐,它更像是“前端发现器”。后续要把它真正变成可用的资产数据,还得靠我自己的脚本去继续加工。
这也是我一直在做的事情: 让 NetBox 继续作为唯一真相源,让自动化发现成为资产建模的入口,而不是终点。
二、CentOS 7 安装 Docker:看起来简单,实际上第一个坑就来了
这个站点是一台 CentOS 7,所以我最开始还是按常规方式装 Docker:
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum install -y docker-ce docker-ce-cli containerd.io
结果一上来就报错。
最开始是仓库拉不下来,后面又提示:
No package docker-ce available.
No package docker-ce-cli available.
No package containerd.io available.
很多人看到这里,第一反应是“Docker 包没了”或者“CentOS 7 不支持了”。
但我后面排下来发现,真正的问题要拆开看:
第一,CentOS 7 这个环境确实太老了。 第二,我那一次 repo 拉取本身就失败了,后面 yum 自然也找不到包。
所以我没有继续盲目重试,而是先确认最底层的问题是不是网络和证书。
我用 curl 和 openssl 去测:
- Docker 官方地址能不能访问
- TLS 握手正不正常
- 证书链有没有问题
排下来发现:
- 服务器能连 Docker 官方地址
- TLS 正常
- 证书正常
这说明问题根本不是“网络不通”,而是 repo 写入和 yum 识别阶段有问题。
所以后面我就不再纠结 yum-config-manager 这一步了,而是直接手工写 Docker 仓库配置。
这一步处理完之后,再重新:
yum clean all
yum makecache
yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
最后成功安装,再执行:
systemctl enable docker
systemctl start docker
docker version
docker info
看到 Docker 服务正常起来,我才算真正进入下一阶段。
这里我的经验是:
在 CentOS 7 这种老系统上,不要迷信“一条命令安装”,而是要先把问题分层。
先确定是不是网络、是不是 repo、是不是系统兼容性,再往下处理,效率反而更高。
三、Docker 装好了,Orb 第一个问题又来了:镜像拉不下来
Docker 启动没问题后,我开始部署 Orb Agent。
我最开始是直接:
docker compose up -d
结果又卡住了,这次报的是 Docker Hub 拉镜像超时。
这类问题如果不拆开处理,很容易误以为是 compose 文件有问题。 但其实这一步最重要的是先确认:到底是“镜像没拉下来”,还是“镜像拉下来了但容器起不来”。
所以我后面先单独执行:
docker pull netboxlabs/orb-agent:latest
等镜像完整拉下来之后,再执行:
docker compose up -d
这个思路其实很简单,但非常重要:
先把“拉镜像问题”和“容器启动问题”拆开。
这样排障不会混在一起。
四、Orb 容器起来了,但其实并没有真正运行
镜像拉下来以后,我第一次看到的核心报错是:
Error: no config file specified, use --config or -c flag to provide config files
这说明一个问题:
Orb 容器虽然已经启动了,但它根本不知道该读哪个配置文件。
也就是说,这种“容器 Up 了”的状态,其实是假的成功。 它只是起来了一下,然后因为没有配置文件路径而不断重启。
所以后面我就把 compose 文件改成显式指定启动命令的方式:
command: ["run", "-c", "/opt/orb/agent.yaml"]
再配合:
volumes:
- ./agent.yaml:/opt/orb/agent.yaml
这个地方我强烈建议不要偷懒。 因为你只把配置文件挂进去,不代表 Orb 会自动知道它在哪。
五、Orb 第二个坑:变量写法没问题,但就是不生效
配置文件路径搞定后,我又踩到了一个更隐蔽的问题。
我一开始在 agent.yaml 里写的是:
client_id: ${DIODE_CLIENT_ID}
client_secret: ${DIODE_CLIENT_SECRET}
从表面看,这种写法一点问题没有。
我也尝试过 .env、env_file 等方式去传变量。
但真正看日志时,会发现一个很诡异的现象:
日志里仍然显示的是:
"client_id":"${DIODE_CLIENT_ID}"
也就是说,它根本没有被真正替换成实际值。
更麻烦的是,这类问题有时候不会马上给你一个非常直白的致命报错,而是表现成:
- policy 能加载
- backend 看起来也启动了
- 但扫描就是不按预期执行
这种问题最容易把人绕进去,因为你会误以为“配置都对了”。
最后我为了快速稳定地把这个站点打通,直接选择了一个最务实的方案:
直接把认证参数写死
我最终能跑通的 agent.yaml,核心配置是这样的:
orb:
config_manager:
active: local
backends:
common:
diode:
target: "grpc://hostname:8080/diode"
client_id: "orb-agent-si te"
client_secret: "你的secret"
agent_name: "orb-agent-site02"
network_discovery:
然后 compose 里也显式写了 environment:
environment:
DIODE_CLIENT_ID: "orb-agent-site02"
DIODE_CLIENT_SECRET: "你的secret"
从工程美观上讲,这不是最优雅的方案。 但从“我要今晚把它跑通”的角度讲,这就是最有效的方案。
我这次最大的感受就是:
现场排障时,优先要的是确定性,而不是最漂亮的写法。
六、为什么我后面这套 Orb 配置能成功
最小闭环
最后我跑通的配置,核心有几个点。
1)配置文件路径明确
我统一用了:
- ./agent.yaml:/opt/orb/agent.yaml
command: ["run", "-c", "/opt/orb/agent.yaml"]
这样 Orb Agent 启动时,路径是明确的,不会猜。
2)认证参数不再依赖不稳定的变量替换
我直接写死 client_id 和 client_secret,彻底绕过“变量到底有没有传进去”这个不确定因素。
3)加了时间同步挂载
我在 compose 里还加了:
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
这一步看起来小,但在排 schedule 的时候非常有帮助。 因为前面我有几次都是“看起来到时间了,结果日志没动”,后来才发现很多时候是自己看错了观察窗口。
4)先做最小闭环,再恢复正式范围
我一开始没有直接扫三个网段,而是先缩成:
- 单个网段
- 每分钟调度一次
- 先验证扫描链路是否真的能跑
等最小闭环跑通了,再恢复成正式调度时间和正式扫描范围。
这一步可以极大降低排错复杂度。
七、Orb 到底有没有真正扫描成功,怎么验证
我这次最有价值的一个排障动作,就是用了 dry run。
也就是先不着急只盯着平台上有没有数据,而是让 Orb 把扫描结果先写成 JSON 到本地目录。
这样做有两个好处:
- 能证明扫描到底有没有真正执行
- 能证明发现结果到底有没有生成
我当时把配置改成了 dry run 以后,很快就在本地目录里看到了扫描结果文件。
随后日志也出现了最关键的几行:
running scanner
discovery complete
hosts_found: "13"
entities ingested successfully
看到这里,其实整个站点就已经打通了。
也就是说,我这个分站点最终成功实现了:
- Orb Agent 正常运行
- network discovery 正常执行
- 发现结果通过 Diode 成功同步
- 主站点 NetBox 成功接收
这才是真正意义上的“成功”。
不是容器起来了,也不是 policy applied successfully,而是:
真正扫到了主机,并且结果成功进入了我的 NetBox 体系。
八、Orb 扫完只是第一步,后面我还要继续补全资产
资产补全
这一步其实是很多人容易忽略的。
Orb 的能力更偏向 发现,它擅长把网段里的 IP 和基础探测结果找出来。 但如果我想让 NetBox 里的资产变成真正可用的模型,还得继续补设备、接口、链路。
所以我后面又接上了自己的 4 个 Python 脚本。
我的目录结构是:
/opt/autotask/
├── .env
└── device-auto/
├── 1_auto_tag_ip_by_snmp.py
├── 2_auto_discover_devices.py
├── 3_snmp_interface.py
└── 4_snmp_lldp_to_cable.py
这 4 个脚本的顺序我不是随便排的,而是按资产建模逻辑来排的。
第一步:给 Orb 发现的 IP 做 SNMP 可达性校验并打标签
脚本 1 的作用是:
- 从 NetBox 中取出 Orb 已发现的 IP
- 根据站点 tag 筛选
- 测试 SNMP 可达性
- 给能管理的 IP 打上
snmp-managed
这一步跑完之后,我才知道哪些 IP 可以继续做设备发现。
第二步:自动创建设备
脚本 2 的作用,是把“IP”补成“设备”。
也就是:
- 根据 SNMP 信息识别设备
- 创建设备对象
- 绑定管理 IP
- 写基础信息
这一步做完,NetBox 才从“有很多 IP”变成“有了一批设备”。
第三步:自动同步接口
脚本 3 是基于 SNMP 把接口同步进去。 设备有了以后,接口才能建。
第四步:基于 LLDP 自动建 Cable
脚本 4 最终完成的是链路层面的自动建模。 没有前面的设备和接口,这一步也没法做。
所以这 4 个脚本一定是一个顺序链路,而不是随便单独跑。
九、CentOS 7 上 Python 环境和 easysnmp 的坑
这一步也是我这次踩得很深的坑之一。
我的脚本依赖这些 Python 包:
pynetboxeasysnmppython-dotenvtqdmrequests
其中最容易出问题的,就是 easysnmp。
为什么 easysnmp 在 CentOS 7 上麻烦
因为它不是简单的纯 Python 包,而是依赖底层 SNMP 开发环境。 在 CentOS 7 上很容易遇到:
- 编译失败
- 头文件缺失
- Python 版本不匹配
- 安装成功但导入失败
如果硬装,排起来会很费时间。
我后来采用的最稳方案:跨服务器迁移已编译好的 easysnmp
这个方法我很推荐,尤其适合像我这种已经有一台成功环境的情况。
核心思路就是:
- 在源服务器上找到已经安装好的
easysnmp - 把整个
easysnmp目录和相关元数据打包 - 传到目标服务器
- 直接解压到目标服务器的
site-packages - 跳过本地编译
这个方案的好处非常直接:
完全绕过编译过程。
对 CentOS 7 这种环境来说,这基本就是最稳的办法。
如果你手头也有一台已经成功安装 easysnmp 的服务器,我真的建议优先这么干,不要反复硬编译。
十、我的定时任务是怎么设计的
脚本都能手工跑通后,我最后再把它们挂到 cron 里。
我机器上的 Python 路径是:
/usr/bin/python3.10
我实际验证成功的运行方式是:
cd /opt/autotask/device-auto
python3.10 1_auto_tag_ip_by_snmp.py
所以我的 cron 也按这个模式写,保持和手工执行尽量一致:
45 2 * * * cd /opt/autotask/device-auto && /usr/bin/python3.10 1_auto_tag_ip_by_snmp.py >> /opt/autotask/logs/cron/1_auto_tag_ip_by_snmp.log 2>&1
0 3 * * * cd /opt/autotask/device-auto && /usr/bin/python3.10 2_auto_discover_devices.py >> /opt/autotask/logs/cron/2_auto_discover_devices.log 2>&1
15 3 * * * cd /opt/autotask/device-auto && /usr/bin/python3.10 3_snmp_interface.py >> /opt/autotask/logs/cron/3_snmp_interface.log 2>&1
30 3 * * * cd /opt/autotask/device-auto && /usr/bin/python3.10 4_snmp_lldp_to_cable.py >> /opt/autotask/logs/cron/4_snmp_lldp_to_cable.log 2>&1
我这里的设计思路是:
-
凌晨 2:45 开始
-
每 15 分钟跑一个脚本
-
顺序完成:
- 打 SNMP 标签
- 创建设备
- 创建接口
- 创建 Cable
这套方案适合先上线观察。 后面如果发现第二个脚本执行时间太长,压到了第三个脚本,再考虑把它改成“一个总控脚本串行执行”。
十一、这次我总结出来最有价值的排错思路
回过头看,这次真正让我节省时间的,不是某一条命令,而是下面这些判断方式。
1)先分层,不要混着查
Docker 是 Docker 的问题,Orb 是 Orb 的问题,SNMP 依赖是 SNMP 的问题。 不要一上来把所有问题混成一坨。
2)“容器启动成功”不等于“业务成功”
Orb 这类组件最容易造成假象。
真正的成功,不是 up,也不是 policy applied successfully,而是:
running scannerdiscovery completeentities ingested successfully
3)最小闭环优先
先扫一个网段、先每分钟跑一次、先 dry run,本地先看到结果,再恢复正式配置。 这比一上来就全量扫描三个网段稳定得多。
4)老系统不要死磕最标准的安装姿势
比如 easysnmp,在 CentOS 7 上我就不建议反复硬编译。
有现成能跑的环境,直接迁移编译好的包,效率远高于原地折腾。
5)定时任务要尽量贴近手工成功路径
我手工怎么跑通的,cron 就尽量怎么写。 这可以避免大量“交互 shell 里没问题,定时任务里就找不到路径”的坑。
十二、最后我的结论
这次这个 CentOS 7 站点,最开始看起来只是个“收尾站点”,但实际上它把整条链路都帮我验证完整了:
- CentOS 7 上 Docker 可用
- Orb Agent 可用
- Diode 同步到主站 NetBox 可用
- Orb 发现结果质量正常
- 后续 Python 自动化补全设备、接口、链路可落地
- 定时任务也能跑通
这对我来说意义很大。
因为它证明了:
NetBox 多站点纳管这条路是能真正跑起来的。
不是停留在“我能扫到几个 IP”,而是已经逐步形成:
- 自动发现
- 自动同步
- 自动建模
- 自动补全
这才是我想要的方向。
写在最后
如果你也在做:
- NetBox 多站点纳管
- Orb / Diode 联动发现
- SNMP 自动发现与资产建模
- 老旧环境(比如 CentOS 7)上的自动化落地
那我这次踩过的这些坑,应该能帮你少走不少弯路。
我后面还会继续整理:
- Orb 多站点最佳实践
- NetBox 自动建模脚本优化
- LLDP 自动建链思路
- 基于发现结果的资产治理方案
如果你也在做类似方向,欢迎来找我交流
我会持续分享我自己在 NetBox、Orb、自动化运维、资产建模 这条线上的实战过程。
关注我,后面我会把这些能力逐步整理成一套完整的方法论和可复用方案。