摘要

  • 这篇文章聚焦多站点发现链路,核心是把 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:

bash
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum install -y docker-ce docker-ce-cli containerd.io

结果一上来就报错。

最开始是仓库拉不下来,后面又提示:

bash
No package docker-ce available.
No package docker-ce-cli available.
No package containerd.io available.

很多人看到这里,第一反应是“Docker 包没了”或者“CentOS 7 不支持了”。

但我后面排下来发现,真正的问题要拆开看:

第一,CentOS 7 这个环境确实太老了。 第二,我那一次 repo 拉取本身就失败了,后面 yum 自然也找不到包。

所以我没有继续盲目重试,而是先确认最底层的问题是不是网络和证书。

我用 curlopenssl 去测:

  • Docker 官方地址能不能访问
  • TLS 握手正不正常
  • 证书链有没有问题

排下来发现:

  • 服务器能连 Docker 官方地址
  • TLS 正常
  • 证书正常

这说明问题根本不是“网络不通”,而是 repo 写入和 yum 识别阶段有问题

所以后面我就不再纠结 yum-config-manager 这一步了,而是直接手工写 Docker 仓库配置。 这一步处理完之后,再重新:

bash
yum clean all
yum makecache
yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

最后成功安装,再执行:

bash
systemctl enable docker
systemctl start docker
docker version
docker info

看到 Docker 服务正常起来,我才算真正进入下一阶段。

这里我的经验是:

在 CentOS 7 这种老系统上,不要迷信“一条命令安装”,而是要先把问题分层。

先确定是不是网络、是不是 repo、是不是系统兼容性,再往下处理,效率反而更高。


三、Docker 装好了,Orb 第一个问题又来了:镜像拉不下来

Docker 启动没问题后,我开始部署 Orb Agent。

我最开始是直接:

bash
docker compose up -d

结果又卡住了,这次报的是 Docker Hub 拉镜像超时。

这类问题如果不拆开处理,很容易误以为是 compose 文件有问题。 但其实这一步最重要的是先确认:到底是“镜像没拉下来”,还是“镜像拉下来了但容器起不来”。

所以我后面先单独执行:

bash
docker pull netboxlabs/orb-agent:latest

等镜像完整拉下来之后,再执行:

bash
docker compose up -d

这个思路其实很简单,但非常重要:

先把“拉镜像问题”和“容器启动问题”拆开。

这样排障不会混在一起。


四、Orb 容器起来了,但其实并没有真正运行

镜像拉下来以后,我第一次看到的核心报错是:

bash
Error: no config file specified, use --config or -c flag to provide config files

这说明一个问题:

Orb 容器虽然已经启动了,但它根本不知道该读哪个配置文件。

也就是说,这种“容器 Up 了”的状态,其实是假的成功。 它只是起来了一下,然后因为没有配置文件路径而不断重启。

所以后面我就把 compose 文件改成显式指定启动命令的方式:

yaml
command: ["run", "-c", "/opt/orb/agent.yaml"]

再配合:

yaml
volumes:
  - ./agent.yaml:/opt/orb/agent.yaml

这个地方我强烈建议不要偷懒。 因为你只把配置文件挂进去,不代表 Orb 会自动知道它在哪。


五、Orb 第二个坑:变量写法没问题,但就是不生效

配置文件路径搞定后,我又踩到了一个更隐蔽的问题。

我一开始在 agent.yaml 里写的是:

yaml
client_id: ${DIODE_CLIENT_ID}
client_secret: ${DIODE_CLIENT_SECRET}

从表面看,这种写法一点问题没有。 我也尝试过 .envenv_file 等方式去传变量。

但真正看日志时,会发现一个很诡异的现象:

日志里仍然显示的是:

json
"client_id":"${DIODE_CLIENT_ID}"

也就是说,它根本没有被真正替换成实际值。

更麻烦的是,这类问题有时候不会马上给你一个非常直白的致命报错,而是表现成:

  • policy 能加载
  • backend 看起来也启动了
  • 但扫描就是不按预期执行

这种问题最容易把人绕进去,因为你会误以为“配置都对了”。

最后我为了快速稳定地把这个站点打通,直接选择了一个最务实的方案:

直接把认证参数写死

我最终能跑通的 agent.yaml,核心配置是这样的:

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:

yaml
environment:
  DIODE_CLIENT_ID: "orb-agent-site02"
  DIODE_CLIENT_SECRET: "你的secret"

从工程美观上讲,这不是最优雅的方案。 但从“我要今晚把它跑通”的角度讲,这就是最有效的方案。

我这次最大的感受就是:

现场排障时,优先要的是确定性,而不是最漂亮的写法。


六、为什么我后面这套 Orb 配置能成功

Orb 配置最小闭环

最小闭环

最后我跑通的配置,核心有几个点。

1)配置文件路径明确

我统一用了:

yaml
- ./agent.yaml:/opt/orb/agent.yaml
command: ["run", "-c", "/opt/orb/agent.yaml"]

这样 Orb Agent 启动时,路径是明确的,不会猜。

2)认证参数不再依赖不稳定的变量替换

我直接写死 client_idclient_secret,彻底绕过“变量到底有没有传进去”这个不确定因素。

3)加了时间同步挂载

我在 compose 里还加了:

yaml
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro

这一步看起来小,但在排 schedule 的时候非常有帮助。 因为前面我有几次都是“看起来到时间了,结果日志没动”,后来才发现很多时候是自己看错了观察窗口。

4)先做最小闭环,再恢复正式范围

我一开始没有直接扫三个网段,而是先缩成:

  • 单个网段
  • 每分钟调度一次
  • 先验证扫描链路是否真的能跑

等最小闭环跑通了,再恢复成正式调度时间和正式扫描范围。

这一步可以极大降低排错复杂度。


七、Orb 到底有没有真正扫描成功,怎么验证

我这次最有价值的一个排障动作,就是用了 dry run

也就是先不着急只盯着平台上有没有数据,而是让 Orb 把扫描结果先写成 JSON 到本地目录。

这样做有两个好处:

  1. 能证明扫描到底有没有真正执行
  2. 能证明发现结果到底有没有生成

我当时把配置改成了 dry run 以后,很快就在本地目录里看到了扫描结果文件。

随后日志也出现了最关键的几行:

text
running scanner
discovery complete
hosts_found: "13"
entities ingested successfully

看到这里,其实整个站点就已经打通了。

也就是说,我这个分站点最终成功实现了:

  • Orb Agent 正常运行
  • network discovery 正常执行
  • 发现结果通过 Diode 成功同步
  • 主站点 NetBox 成功接收

这才是真正意义上的“成功”。

不是容器起来了,也不是 policy applied successfully,而是:

真正扫到了主机,并且结果成功进入了我的 NetBox 体系。


八、Orb 扫完只是第一步,后面我还要继续补全资产

Python 补全 NetBox 资产链路

资产补全

这一步其实是很多人容易忽略的。

Orb 的能力更偏向 发现,它擅长把网段里的 IP 和基础探测结果找出来。 但如果我想让 NetBox 里的资产变成真正可用的模型,还得继续补设备、接口、链路。

所以我后面又接上了自己的 4 个 Python 脚本。

我的目录结构是:

bash
/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 包:

  • pynetbox
  • easysnmp
  • python-dotenv
  • tqdm
  • requests

其中最容易出问题的,就是 easysnmp

为什么 easysnmp 在 CentOS 7 上麻烦

因为它不是简单的纯 Python 包,而是依赖底层 SNMP 开发环境。 在 CentOS 7 上很容易遇到:

  • 编译失败
  • 头文件缺失
  • Python 版本不匹配
  • 安装成功但导入失败

如果硬装,排起来会很费时间。

我后来采用的最稳方案:跨服务器迁移已编译好的 easysnmp

这个方法我很推荐,尤其适合像我这种已经有一台成功环境的情况。

核心思路就是:

  • 在源服务器上找到已经安装好的 easysnmp
  • 把整个 easysnmp 目录和相关元数据打包
  • 传到目标服务器
  • 直接解压到目标服务器的 site-packages
  • 跳过本地编译

这个方案的好处非常直接:

完全绕过编译过程。

对 CentOS 7 这种环境来说,这基本就是最稳的办法。

如果你手头也有一台已经成功安装 easysnmp 的服务器,我真的建议优先这么干,不要反复硬编译。


十、我的定时任务是怎么设计的

脚本都能手工跑通后,我最后再把它们挂到 cron 里。

我机器上的 Python 路径是:

bash
/usr/bin/python3.10

我实际验证成功的运行方式是:

bash
cd /opt/autotask/device-auto
python3.10 1_auto_tag_ip_by_snmp.py

所以我的 cron 也按这个模式写,保持和手工执行尽量一致:

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 scanner
  • discovery complete
  • entities 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、自动化运维、资产建模 这条线上的实战过程。

关注我,后面我会把这些能力逐步整理成一套完整的方法论和可复用方案。