Nightingale 主机接入失败排查指南:用 host-onboard-diagnose 沿着 5 段接入链路定位问题
【免费下载链接】nightingaleNightingale is to monitoring and alerting what Grafana is to visualization.项目地址: https://gitcode.com/GitHub_Trending/ni/nightingale
导读:本文围绕 Nightingale 内置 AI 技能host-onboard-diagnose展开,它是专门用于排查"categraf 已安装、进程也在跑,但主机就是不显示在主机列表里,或显示为 unknown、没有任何指标"这类接入失败问题的诊断方案。读者读完将掌握:接入链路 5 段拆解法、probe_target_onboard_status探针工具的使用、按likely_segment分支的决策表、段 5 的三条变体 PromQL 查询,以及一套可直接落地的修复命令与自验证方法。
一、适用范围:什么时候进入这个技能
host-onboard-diagnose是 Nightingale AI 助手内置技能之一,完整定义见 SKILL.md,技能声明位于其 frontmatter(name: host-onboard-diagnose,max_iterations: 18,内置probe_target_onboard_status、list_targets、get_target_detail、query_prometheus、query_host_metrics_window、list_datasources等工具)。
应当进入本技能的典型提问:
- "我新装的 categraf 主机没有出现在 Nightingale 里"
- "agent 装好了也在运行,但主机列表里看不到这台机器"
- "列表里这台主机的 OS / CPU / 版本全部是 unknown"
- "我用 Helm 部署了 3 台 categraf,平台只看到 1 台"
- "我在 Windows 上装了 agent 但注册不上"
- "改完 hostname 后主机立刻消失了"(categraf 还在运行的情况)
不应进入本技能的典型场景(避免与相邻技能混淆):
- 之前一直可见、最近才失联 → 走 host-health-diagnose,两者是互斥的:host-health 处理"曾经接入过、现在失联",而 host-onboard 处理"从头到尾就没接入成功";
- ident 重复 / 改名后残留清理 → 走
host-ident-cleanup(规划中); - 想改告警规则 / 屏蔽 → 走
creation/create-alert-rule; - 排查某条告警为何没触发 → 走
alert-rule-troubleshoot。
一句话原则:缺失主机 ≠ 单一原因。只看heartbeat.enable就让人改 categraf 配置是最高频的坑——很多用户改了依然看不到主机,因为问题其实出在omit_hostname/ ident 计算 shell / TLS / token / edge redis / 多集群路由上。
二、核心模型:接入链路 5 段拆解
技能的核心心智模型是把"主机接入"拆成一条 5 段流水线,每一段卡住的表现都不一样:
[1] categraf 本地进程 进程在不在 / 配置对不对 / heartbeat.enable 是否开启 │ [2] heartbeat 上报 HTTP 能否连通 /v1/n9e/heartbeat(网络 / TLS / BasicAuth) │ [3] server / edge 接收 token / 版本兼容性 / hostname 重复校验 │ [4] target 表持久化 该 ident 是否在 DB 中,meta 是否进了 redis │ [5] Redis + 指标流 时序库能否为该 ident 找到样本从源码结构看,这条链路与 Nightingale 的实际数据流完全对应:categraf 通过心跳接口上报(安装脚本 install-categraf.sh.tmpl 中明确出现了${N9E_HOST}/v1/n9e/heartbeat这一地址,脚本会校验配置中是否写入了该 URL),中心侧收到心跳后把心跳时间与 meta 写入 Redis(key 形如n9e_meta_update_time_<ident>、n9e_meta_<ident>,见host_health.go中readRedisHostState的读取逻辑),同时把 target 行持久化到 DB;categraf 采集到的指标则通过[[writers]]写入时序库。
只盯其中一段就让人改配置是常见误区。正确姿势是:先收集证据,再逐段定位,最后给出修复命令。
三、第一步(强制):调用probe_target_onboard_status
这是本技能唯一的诊断入口工具,一次调用就能返回 5 段的足迹。它的实现位于 host_onboard.go,其设计出发点(源码注释)是:与get_target_realtime_status的关键差异在于容忍 target 不在 DB 中——这正是 onboard 场景的常态,"机器没出现"时 target 行往往根本就没落库,老式 host_health 系列工具直接返回target not found就断了。
关键返回字段与段位的对应关系:
| 返回字段 | 对应段位 | 含义 |
|---|---|---|
in_target_db+target.os+target.agent_version | 段 3/4 | DB 是否落库、元数据是否完整 |
in_redis_beat+redis_meta.hostname+redis_meta.remote_addr | 段 4 | Redis 心跳与 meta 是否存在 |
in_prom_target_up+target_up_last+prom_metrics_hit | 段 5 | 时序库能否查到该 ident |
likely_segment+likely_causes | 聚合诊断 | 工具层已预聚合,不要绕过它自己反推 |
从 defs.go 中ProbeTargetOnboardStatus的定义可以看到完整的参数约定:ident必填;datasource_id可选,不传时按 chat-level params 兜底,仍取不到则跳过段 5,不报错(段 5 不是 fatal 的)。权限上,target 在 DB 且有业务组归属时按组交集鉴权;target 不在 DB 或未归组时允许查询——因为接入排障必须能查"还没归过组"的机器,否则用户会被自己的权限锁死(源码host_onboard.go中有明确注释说明这一点,与host_health.go的严格鉴权形成对照)。
实现细节(见probeTargetOnboardStatus):段 3/4 通过models.TargetGet(deps.DBCtx, "ident=?", ident)查 DB;段 4 复用readRedisHostState读心跳时间与 meta;段 5 用target_up{ident="..."}与system_load1{ident="..."}两条 instant 查询(后者是兜底:心跳挂着但用户不上报 target_up 的奇异情形也能识别),escapePromLabel负责转义 ident 中的反斜杠与双引号。最后diagnoseOnboardSegment按"最深一段有证据的位置"折叠出likely_segment——规则按段位倒序判断,一旦命中就返回,避免把"DB 有 + redis 也有"误判成段 3 问题。
如果用户没提供 ident,先调用list_targets让用户挑选,或按 OS=unknown / agent_version 为空过滤出候选(即"未归组 / 半接入"视图)。
四、决策表:按likely_segment分支
拿到likely_segment后按表行动,likely_causes已附带高频根因列表:
likely_segment | 含义 | 首选修复动作 |
|---|---|---|
segment_1_or_2 | DB / redis / prom 三处都没有这台主机 | 到目标主机上:systemctl status categraf→journalctl -u categraf --since "5 min ago",看是否报connection refused/x509/401 |
segment_3 | target 存在但 OS / agent_version 为空 | 检查 categraf 的config.toml:[heartbeat] enable=true且omit_hostname=false;版本 ≥ v0.2.35 |
segment_4 | target 已落库但 redis 里没数据 | 检查 n9e/edge 是否配置了 redis;edge 模式下看edge.toml的[Redis];n9e 与 n9e-edge 版本是否一致 |
segment_5 | redis 有 beat 但 prom 查不到 | 检查 categraf[[writers]]是否配置;多集群部署下数据源是否正确;ident 是否含()[]*等特殊字符 |
ok | 接入正常 | 用户仍坚持"看不到",引导刷新页面 / 检查业务组过滤 / 浏览器缓存 |
从源码看,diagnoseOnboardSegment的判定逻辑(host_onboard.go)与上表一一对应,且每条likely_causes都带 issue 编号作为证据链。例如segment_5的高频根因包括:[[writers]]未配置或 url 错、omit_hostname=true导致 ident 标签丢失、多集群下 categraf 与 server 走的数据源不一致(redis 注册到了中心但时序写到了别处)、ident 含特殊字符导致 PromQL 精确匹配失败。
五、段 5 专用:三条变体 PromQL 查询
当likely_segment=segment_5时,必须用query_prometheus依次执行以下 3 条查询,确认是 ident 标签问题还是真的没数据:
# 1. 标准 ident 精确匹配(最常见) target_up{ident="<ident>"} # 2. 模糊匹配(ident 带 IP 前缀 / 别名时用) target_up{ident=~".*<host>.*"} # 3. 极端兜底:是否落到了 instance 标签上(snmp / 自定义 tag 场景) {instance=~".*<host>.*"}判定逻辑:
- 三条全空 → 数据流确实从未到达 prom,回头查 categraf writers / TLS / n9e ingest 队列;
- 仅 (2) 或 (3) 有数据 →ident 标签问题(特殊字符 /
global_labels覆盖 / snmpagent_host_tag误用),引导用户走host-ident-cleanup(规划中)或修复 categraf 配置。
六、输出模板(强约束)
最终回答必须使用 Markdown、使用用户语言,且严格四段结构:
## Conclusion <一句话:卡在段 X:xxxx(或:接入正常,你看不到的原因是 yyy)> ## Onboarding Pipeline Evidence - 段 1/2(categraf 本地/HTTP):<未采集 / 推断异常:xxx> - 段 3(server 接收):target in_db=true, os=unknown, agent_version="" → 心跳元数据未持久化 - 段 4(target 持久化 + redis):target update_at=2026-05-14 10:23:11 但 redis 无心跳 - 段 5(Prom):target_up 无数据 / prom_metrics_hit=0 ## Fix Commands 1. 在目标主机上执行: grep -E 'heartbeat|omit_hostname' /etc/categraf/conf/config.toml 期望:heartbeat 段 enable=true, omit_hostname=false。若不满足,修改后 systemctl restart categraf。 2. ... 3. ... ## Self-Verification Steps <给用户 1-2 条"想确认是否修好,可以这样验证"的命令,例如: - 重启 categraf 后 30 秒内回到平台刷新主机列表,OS/CPU 字段应不再是 unknown - curl -s http://<n9e>:17000/api/n9e/self-metrics | grep <ident>>从源码角度,输出模板里的证据字段与probe_target_onboard_status的 JSON 返回结构一一对应(onboardTargetSnap/onboardRedisSnap/onboardProbeResult三个结构体),也就是说最终回答里每一个证据项都应是探针返回的真实字段值,而不是"看起来正常"这种模糊表述。
七、反模式(明确禁止的行为)
- ❌ 不调用
probe_target_onboard_status就直接让用户改heartbeat.enable。先收集证据——很多用户早就开了 heartbeat,问题在 omit_hostname / TLS / 版本。 - ❌ 看到
in_target_db=false就说"categraf 没装"。必须综合 redis 段与段 1/2 的原因整体判断是网络问题还是进程问题——两者的推荐动作完全不同。 - ❌ 段 3 卡住时只让改 heartbeat 而不提 omit_hostname / 版本,这两者同样常见。
- ❌ 段 5 卡住时不跑 3 条变体 PromQL 就让用户改 writers——ident 标签问题同样会卡在段 5。
- ❌ 输出不给具体命令,只说"检查一下 categraf 配置"。每条建议都必须是用户能直接复制粘贴执行的。
八、各段已知故障模式(速查)
- 段 1/2:categraf 连不上 center(connection refused)、TLS 未知证书颁发机构、自签证书、BasicAuth 无效、ams token 不匹配、Helm 多节点只见 1 台、Windows 场景、Win2008 不支持。
- 段 3:
heartbeat enable=false、未知字段 /omit_hostname=true、categraf 版本过低(v6 要求 v0.2.35+)、identity 计算 shell 拿不到 IP、hostname 重复。 - 段 4:edge redis 为 nil、n9e 与 n9e-edge 版本不匹配、CenterApi 缺失、edge 部署下中心看不到主机、redis
maxmemory-policy把心跳 key 驱逐。 - 段 5:带括号的 ident 在 dashboard 里查不到、host=* bug、snmp ident 冲突、
omit_hostname=true导致 ident 标签丢失、多集群下数据源选错、写入队列满 499、global.labels覆盖。
九、输出风格与收尾判断
- 结论放第一段第一行,不卖关子。
- 证据必须给具体字段值,不写"看起来正常"。
- 修复命令必须可直接粘贴执行。
- 用用户的语言回答(中文用户用中文,英文用户用英文)。
- 如果
likely_segment=ok但用户坚持看不到,提示依次检查:业务组过滤(主机其实在,只是被前端业务组隐藏)、浏览器缓存、登录用户的可见业务组权限。
十、与相邻技能的协作关系
本技能与 host-health-diagnose 是接入与健康两大诊断方向的分工:前者回答"为什么从没接进来",后者回答"为什么现在失联了"。两者的工具族也有明确分工——onboard 用probe_target_onboard_status(容忍 target 不在 DB),health 用get_target_realtime_status(target 不存在直接报 not found)。两个技能在 actions.go 中被统一注册为可用动作,形成互补。结合 defs.go 中的工具定义与 host_onboard.go、host_health.go 的实现,读者可以完整追溯"诊断结论 → 证据字段 → 底层数据源(DB / Redis / Prometheus)"的整条链路,将这套方法论复用到自己的接入排障实践中。
【免费下载链接】nightingaleNightingale is to monitoring and alerting what Grafana is to visualization.项目地址: https://gitcode.com/GitHub_Trending/ni/nightingale
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考