BGP连接成功与HTTP响应之间的四个层次
一句话总结
BGP peer 处于 Established,只能证明路由交换连接已经建立,不能证明用户的 HTTP 请求成功。本模块会在同一 server 前放置五个 router,分别比较 peer 连接、接收路由的 RIB、kernel 转发路由的 FIB,以及真实响应。目标是不把不同故障笼统归为同一种 timeout,并说明每项观测最多能够支持什么结论。
为什么需要它
值班界面显示五个 peer 中有四个是绿色,但服务负责人仍然无法连接。此时若重启所有 agent,路由可能暂时改变,旧日志也可能消失,让根因更难查找。首先应询问:运维人员确认的成功,与用户期待的成功是否是同一件事。建立 TCP 连接、学习 prefix、把 route 写入 kernel,以及收到 server 响应,都是不同事件。
实验中包含 AS number 错误的 peer、仅建立连接的 peer、能学习路由却不安装进 kernel 的 router,以及能够正常转发的 router。为了修复一个对象时不破坏其他对照,每个 router 都放在独立 Linux network namespace 中。各 namespace 的 interface 与 routing table 相互隔离,但全部位于个人 VM 内,不会触碰家庭 router 或平台的生产 BGP。以下地址只用于实验内部,不能原样搬到真实组织的路由配置。
工作原理
先读取地址,再确认连接方向
每个 router 都通过 veth 与 VM 直接连接。VM 侧 Cilium 的 AS 是 65001,router 侧 FRR 的 AS 是 65002。Cilium 的 peerASN 必须填写对端 FRR 的 65002;反过来,FRR 的 remote-as 则填写 Cilium 的 65001。local 与 remote 并不是永远固定在文档中的方向,它们会随当前正在读取哪台设备的配置而变化。
| 对照 router | VM interface 与 IP | router IP | 作用 |
|---|---|---|---|
| empty | bgp-empty, 192.0.2.1 | 192.0.2.2 | 修正错误 AS 后,维持没有 advertisement 的连接 |
| rib | bgp-rib, 192.0.2.5 | 192.0.2.6 | 学习 PodCIDR,但不安装进 kernel |
| pod | bgp-pod, 192.0.2.9 | 192.0.2.10 | 学习 PodCIDR,并真正转发到 Pod |
| vip | bgp-vip, 192.0.2.13 | 192.0.2.14 | 只能访问选定 service VIP |
| withdraw | bgp-withdraw, 192.0.2.17 | 192.0.2.18 | 只撤回初始 service 的 advertisement |
每个连接网段都是 /30,router interface 名称为 router。FRR 被动等待连接,由 Cilium 发起连接。只有 empty peer 的 Cilium peerASN 被错误设置为 65003。第一次恢复不应重建整个网络,而只需把该值改为 65002。sourceInterface 会为每个 peer 指定对应的 VM veth,因此也能区分误用其他连接网段地址建立连接的问题。请在 Cilium BGP 资源与 peer 设置中确认配置的各个方向。
PodCIDR advertisement 与 kernel route 不是同一步
CiliumBGPAdvertisement 的 PodCIDR 会发布分配给节点的 Pod network。本实验的完整 pool 是 10.42.0.0/16,但实际分配给节点的范围必须从 CiliumNode 读取。观测工具还会确认真实 Pod IP 是否落在该范围内。如果凭记忆填写整个 /16,或用未观测到的地址填表,就无法判断 route 属于哪个节点。
rib router 被刻意配置了 FRR bgp no-rib。在此状态下,BGP RIB 仍可能显示收到的 best route,但 kernel 不会安装该 route。学员在这里不应把所有 router 都修复成相同状态,而要保留这个对照,并解释 HTTP 失败的原因。pod router 同样接收 PodCIDR advertisement,但允许 FRR 把 route 安装进 kernel,再与 HTTP 200 比较。两个 router 得到不同结果才是正常状态。阅读 FRR 8.4 的 no-kernel 与 no-rib 说明时,也要确认 RIB 一词指的是哪一层的 table。
检查 FIB 时,不能只看 destination prefix,还要对照 protocol 是否为 bgp、next hop 是否为相应连接网段的 VM 地址、output device 是否为 router。通过 default route 或 static /32 获得成功,并不能证明 BGP 转发成功。iproute2 JSON 可能将 /32 destination 显示为不带 suffix 的 IP,因此应比较规范化后的 network,而不是字符串形态。
分离 IP 分配与 service advertisement
LoadBalancer IPAM 为 service 分配地址。获得地址并不表示外部 router 已经知道该地址。第 5 步只会创建学员 pool 203.0.113.10~11,并确认 selected 与 excluded service 获得不同地址。二者使用相同 backend selector,指向同一个 HTTP Pod。在此状态下,不能仅凭地址就断定已完成 advertisement。请在 LB IPAM 中把地址分配与 BGP advertisement 视为两项独立职责。
第 6 步通过 CiliumBGPAdvertisement 的 service selector 只选择 publish=selected。vip router 必须拥有 selected 的准确 /32,不能额外加入 excluded 的 route 或 PodCIDR。即使相同 backend 正常运行,excluded 仍应无法访问。若只确认一个成功响应,就可能漏掉误将两个 service 都公开的配置,因此必须同时测试应成功与应失败的目标。还要区分两个 selector 层次:PeerConfig 选择 advertisement resource,advertisement resource 再选择 Service。
撤回不等于关闭 server
用于撤回对照的 service cca-retire 会预先获得独立于学员 pool 的 203.0.113.20。初始化流程会确认真实 advertisement UID、service UID、RIB/FIB 与 HTTP 200,然后保存 baseline.json。学员要读取这些证据,只删除 cca-withdraw advertisement。HTTP server 与 service 仍然存在,peer 也仍为 Established,但 withdraw router 的 destination route 消失,连接应随之失败。
通过删除 service 或 peer 来制造失败,是另一种实验。若 destination server 本身消失,就无法隔离 advertisement 撤回的效果。因此,评分会确认初始 Pod、node、service UID 是否保持不变,并对照当前 peer、route 与新 HTTP 请求。Cilium 的 advertisement 变更会异步传播,所以不能假设 delete API 返回后 route 就立即消失,应等待观测命令确认收敛后再评分。BGP 运维指南同时讨论 control plane 变更与转发连续性。
相同连接失败也必须结合 routing table 解读
不能仅凭 curl 退出码 7 就断定 route 缺失。即使 route 存在,如果目标端口拒绝连接,也可能得到相同退出码。本实验会结合三项证据:同一 server 通过 pod router 能正常响应、失败 router 的 RIB/FIB 中没有 destination route。相反,rib 对照中 RIB 存在而 FIB 不存在,因此即使 HTTP 结果与 empty 相同,停止的层次也不同。不要把数字相同的结果合并成同一个原因,这是 incident report 的核心。
即使观测工具已经总结失败原因,也应直接阅读原始信息。首先用 kubectl get ciliumbgpclusterconfig cca-bgp -o yaml 查看预期 AS、peer 与 status condition,再用 cilium bgp peers 查看连接状态。然后,对照各 router 的 show bgp ipv4 unicast json 和 ip -n cca-pod -j route show。如果只有配置已保存的证据,router 却没有收到 route,可能是 advertisement 尚未收敛,或 selector 不匹配。此时修改 service deployment,就是触碰了错误层次。
如果 status condition 出现 NoMatchingNode,应先检查 node selector;出现 MissingPeerConfigs,则先确认引用的 PeerConfig 是否存在。这些 condition 可以缩小根因范围,但 condition 消失并不能证明 HTTP 已成功。在本实验这类需要保留初始 peer 与 server 的任务中,即使回滚错误实验,也必须记录修改了什么。用同一个名称创建新 object 会产生不同 UID,旧记录将不再是同一环境的证据。
现场会遇到的情况
LabHub 的流程探测发现,单个 VM 内的 router namespace 与真实外部机器并不完全相同。如果 socket-LB 在 connect 时把 VIP 改写为 Pod IP,那么原本以为在测试外部 router 的 VIP route,实际上可能测试的是 Pod route。本环境从首次安装起就启用了 socketLB.hostNamespaceOnly,并通过 veth packet processing 进行对照;在多个 veth 中,还明确指定 direct routing device。这不是适用于所有生产故障的万能配置,而只是测量环境的条件。请同时阅读 socket-LB 绕过与设备选择中的前提。
失败也必须准确命名。当 curl 以 7 结束且输出 000 时,本实验将其记录为连接失败。000 不是 server 返回的 HTTP code,不能把它写成与应用 HTTP 500 或 NetworkPolicy timeout 相同的问题。反过来,HTTP 200 如果来自其他 server 也不足以作为证据,因此真实 server 会在响应中返回本次 request identifier。报告应将当前 resource UID 与配置 hash、各 router 的 route,以及不同请求的响应组合在一起。
下一项实验要做什么
记录初始环境 identity,并修正一个错误的 peer AS。随后构建仅有 RIB 的对照与真实 Pod 转发,并分离地址分配和选择性 advertisement。最后,撤回初始 service 的 advertisement,生成同时保留五种状态的报告。配置变更或 Pod 重建后,不得复用旧报告。本实验是个人 VM 中 IPv4、单节点的对照,不能扩大声称已经验证多物理节点的 ECMP 分发或 failover。