K8s网络不通先查哪一跳?Radar网络路径诊断Reachability静态追踪+主动探测原理详解
【免费下载链接】radarThe missing open-source Kubernetes UI with a built-in MCP server for AI agents. See what's broken, why, and what changed. Issues, Topology, event timeline, Helm, GitOps, live service traffic, and cluster audits - all in one Go binary.项目地址: https://gitcode.com/gh_mirrors/radar32/radar
当你遇到Kubernetes 网络不通时,最痛苦的不是"服务挂了",而是"不知道断在哪一跳"——Ingress、Service、Endpoints、Pod,任何一环都可能出问题。开源 Kubernetes UI 工具Radar的Reachability(网络可达性)网络路径诊断功能,专门回答一个问题:如果流量发往这个资源,它能不能到达健康进程?如果不能,第一跳断在哪里?
Radar 是单二进制的开源 K8s UI,内置拓扑、资源、Helm、GitOps、流量、审计与 MCP 服务器。Reachability 于 v1.9.1 引入,支持 Service、Ingress、HTTPRoute/GRPCRoute、Gateway 四类网络入口资源,官方文档见 docs/reachability.md。
为什么 K8s 网络故障排查这么难?
传统排查方式是逐层kubectl get+curl:DNS 解析了吗?Ingress 有 backend 吗?Service selector 匹配到 Pod 吗?Pod Ready 了吗?每一跳都要人肉确认。
Radar 的做法是把整条路径画成一张按流量方向排列的跳(hop)图,并给每一跳附上:
- 资源引用(Kind / Namespace / Name)与边标签(如
HTTPRoute → Service) - Findings:复用 Radar 已有问题管道的检测结果,挂到故障可观测的那一跳
- kubectl 复现命令:每条 finding 都自带一条可直接粘贴的排查命令
心智模型:Upstream 并行,Downstream 链式
Radar 把路径分成两段,判定逻辑完全不同:
| 方向 | 结构 | 判定规则 |
|---|---|---|
| Upstreams(指向主体的入口) | 并行 | 多个 Ingress 各判各的;只有全部 broken 才整体 broken |
| Downstream(从主体向下的链路) | 链式 | Service → 选中的 Pods;第一个 critical 发现即brokenAt(断点) |
这意味着一个 Service 同时被 Ingress A 和 Ingress B 引用时,A 坏了不代表 Service 坏了——B 还在正常送流量。
下图展示了一个 Service 同时被 Ingress 和 HTTPRoute 两个入口引用的场景,Radar 对每个入口独立判定,右侧面板显示 HTTPRoute 未挂载到任何 listener:
原理详解:静态追踪层(永远在线)
静态层回答"配置接对了吗",实现在 internal/trace/trace.go:
纯函数跑在内存 informer 缓存上 零逐次 API 请求 · 零 RBAC 请求 · 零用户配置它检查每跳的 declared 配置 + 当前 Pod 状态:端口是否存在(如gwroute:backend-port-mismatch:HTTPRoute 引用了不存在的 Service 端口)、Gateway 路由的父条件(Accepted=False/ResolvedRefs=False)、Pod 的 selected/ready 数量、headless 与无 selector 标记等。
性能目标:典型 <100ms,200 Pod 的 namespace <300ms;打开 Reachability 标签页时 UI 每 5 秒轮询一次,客户端缓存保证切页秒开。
刻意不做的事(保持可信):
- 不读 EndpointSlice——端点信号用 Pod readiness 近似,并诚实标注
endpointSource: pod-readiness - NetworkPolicy 只预测、不裁决——CNI 才是唯一执行权威,Radar 给出的是"集群网络规则会拦截这些 Pod 的流量"这类预测性警告
- 不加新 CRD——一切来自 Radar 既有的 informer 缓存
原理详解:主动探测层(DNS/TCP/TLS/HTTP 分层)
主动层回答"真发一个请求,哪层先失败"。核心探测实现在 pkg/probe/probe.go,每一层有严格超时,高层成功严格蕴含低层成功:
| 层 | 超时 | 说明 |
|---|---|---|
| DNS | 250ms | 解析声明的主机名,区分 split-horizon 场景 |
| TCP | 700ms | 直连 ClusterIP:port 或 PodIP:port |
| TLS | 1s | HTTPS 才走;证书信任失败 ≠ 不可达 |
| HTTP | 1s | 仅 HTTP 形态端口;非 HTTP 端口(如 Redis 6379)止步于 TCP |
总预算 3 秒,各跳并行执行,单个死跳不会拖垮整轮。打开标签页时自动跑一次代理视角探测(Run test可重跑),In-cluster Job 测试保持手动点击。
关键设计:探测目标必须来自集群声明的配置(Service 端口、Ingress 地址、Gateway listener),不接受用户随手输入的 URL;同时内置 SSRF 防护,拒绝直接探测回环地址、link-local 地址(含云厂商 metadata 端点 169.254.169.254、100.100.100.100 等)。
一个 Ingress 主体的典型探测
Radar 从你的机器拨打 Ingress 声明的主机名(DNS → TCP → TLS → HTTP),后端应答 308 重定向。注意顶部判定措辞的克制:
非 HTTP 服务与双协议端口
Redis 这类非 HTTP 服务只验证到 TCP,底部明确标注"TCP connections only — application protocol not checked",绝不冒充应用层可达:
kube-dns 在 53 端口同时声明 TCP 和 UDP,Radar 把两条路径拆开:TCP 可测,UDP 保留为明示的缺口而不是悄悄吞掉:
观测点(Vantage):从哪打决定证明了什么
这是 Radar 最核心的概念——探测结果脱离"从哪发起"毫无意义。界面围绕两个显式选择构建:
- 测哪条路径(PATH 选择器,每条声明路由一行)
- 从哪个观测点(三种视角胶囊):
- Radar on your machine:作为客户端直拨
- API-server proxy:经 K8s API 的
/proxy/子资源中继 - In-cluster probe:集群内一次性探针 Pod
切换观测点会真正重绘路径图、重算判定——笔记本上的成功永远不会被画进 in-cluster 泳道。Radar 宁可说"从这个视角无法确认",也绝不给健康路径泼脏水。
In-cluster 探针:一次性自毁 Job 的安全模型
集群内测试创建短命 Job 跑radar probe,实现在 internal/reachability/runner.go。这是整个诊断面唯一的变更操作,因此被重重设防:
| 防线 | 细节 |
|---|---|
| RBAC 预检 | 创建前逐项校验create jobs/list pods/get pods/log,缺一项直接拒绝并给可复制的 kubectl 兜底命令 |
| Pod 规格 | non-root、只读根文件系统、drop ALL capabilities、不挂载 SA token |
| 生命周期 | 25 秒 ActiveDeadline、60 秒 TTL 兜底清理、单次调用最多 5 个 Job |
| 镜像解析 | 四级回退:显式--reachability-image→ 自读 radar 自身运行镜像 →RADAR_IMAGE环境变量 → 版本匹配的公开镜像 |
| 结果折叠 | 探针 Pod 身份与真实客户端不同,其失败只作信息参考,绝不升级静态判定 |
权限不足时 Radar 会降级为一条可直接复制执行的 kubectl 命令(参数与 Job 完全一致),而不是给你一个误导性结果。
判定语义:四种结论 + 结果可信度
路由结果(outcome)滚动汇总为判定(verdict):
| 判定 | 触发条件 |
|---|---|
| healthy | 所有被测路由在真实流量上可达 |
| degraded | 5xx、部分路由失败、或良性 scale-to-0(读作琥珀色而非红色) |
| broken | 真实路径上出现不可达 |
| unknown | 无法主动测试,或仅经 API-server 代理可达——永不给自信的绿色 |
每个路由还带独立的可信度:real(按真实流量方式测试,可设定判定)与indirect(仅经 API-server 代理,只标注、不置绿)。把unknown当作"暂停并调查"信号——它意味着追踪无法诚实回答,而不是"一切正常"。
探针失败但业务正常?先怀疑视角,再怀疑工作负载
配置健康但探测失败时,常见四因(均与负载本身无关):
- Service mesh mTLS(Istio/Linkerd):网外探测无 mesh 证书,TLS 层必失败——识别特征:Pod 带
istio-proxysidecar 或 mesh 标签。此时应信任集群内测试 - NetworkPolicy:策略放行真实负载间流量、却拦了 Radar 的代理身份
- DNS split-horizon:内部域名在你的笔记本上解析不出来,探测以"附原因的跳过"呈现而非失败
- API-server 中继限制:中继被拒或拨不到仅内部地址
处理方式:跑Test in-cluster从真实数据平面探测;若真实流量确实被丢,去 Traffic 视图的逐流面板看插件上报的原因与 NetworkPolicy 归因。
小结
Radar Reachability 的设计哲学可以浓缩为一句话:把"网络不通"变成"第一跳断在哪",并且每个结论都带着它从哪个视角、用什么证据得出。
- 静态追踪:纯缓存函数,永远在线,回答配置是否正确接线
- 主动探测:DNS/TCP/TLS/HTTP 分层 + 3 秒预算,回答真实请求走到哪层失败
- 观测点一等公民:笔记本 / API-server 中继 / 集群内探针,三泳道互不污染
- 安全边界:RBAC 预检 + 自毁探针 Job + 可复制 kubectl 兜底
AI Agent 同样受益:内置 MCP 服务器的通用diagnose工具对网络入口类资源直接返回这份路径化诊断(传in_cluster: true可跑集群内探测),一次调用拿到路径形状的答案。
📚 更多资料:
- 官方功能文档:docs/reachability.md
- 静态路径追踪源码:internal/trace/trace.go
- 分层探测实现:pkg/probe/probe.go
- 集群内探针 Runner:internal/reachability/runner.go
- 多路由探针编排:internal/reachability/incluster.go
【免费下载链接】radarThe missing open-source Kubernetes UI with a built-in MCP server for AI agents. See what's broken, why, and what changed. Issues, Topology, event timeline, Helm, GitOps, live service traffic, and cluster audits - all in one Go binary.项目地址: https://gitcode.com/gh_mirrors/radar32/radar
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考