路由器已经连接,为什么服务仍然不可达
目标
在真实的 Cilium、FRR 和 Linux 路由器中区分 BGP 会话、RIB、FIB 与 HTTP 各自能证明什么。
为什么重要
把路由通告成功误认为服务可达,会让排障方向完全错误。还要保留失败对照,与正常转发比较,并且只撤回通告,不关闭服务器或 peer。所有操作仅限此个人 VM 的 k3s。准备可能需要几分钟,环境使用 Cilium 1.20.1、FRR 8.4.4、k3s 1.35.8+k3s1。本实验为 IPv4 单节点环境,不能替代多物理节点故障转移测试。
所有任务资源都要添加 metadata.labels.lab=cca-bgp。不要修改或删除初始 5 个 PeerConfig、HTTP Pod、cca-retire 地址池与服务。不要添加默认路由、静态绕行或其他策略。步骤准备不会覆盖已有文件,保存错误的文件必须自行修复;若修改对象,也要更新观测记录。会话结束时文件会消失,请先导出所需资料。
步骤
- 将观测工具 inventory 输出保存到 /root/cca-bgp/inventory.json。读取 Pod 与 CiliumNode 的名称和 UID、真实 Pod IP、已分配 PodCIDR,以及 5 个路由器的 netns、两端 IP 和 AS。不要用整个 10.42.0.0/16 代替节点分配范围。
- 读取初始 CiliumBGPClusterConfig cca-bgp,将修改版本保存到 /root/cca-bgp/peers.yaml 并应用。保留 nodeSelector 的 kubernetes.io/os=linux、实例名 cca 和 localASN=65001。只把 empty peer 错误的 peerASN=65003 改为 65002。保留包括 rib、pod、vip、withdraw 在内的 5 个 peer,以及 peerAddress、peerConfigRef。empty 应为 Established,但没有目的通告,Pod 连接应失败。
- 在 /root/cca-bgp/rib.yaml 中编写并应用 CiliumBGPAdvertisement cca-rib。标签为 lab=cca-bgp 和 advertise=rib,spec.advertisements 只含一个 advertisementType=PodCIDR 条目。rib 路由器应在 RIB 中有真实节点 PodCIDR 的有效最优 BGP 路由,但 FIB 中没有。保留 FRR 初始 bgp no-rib,并与 Pod HTTP 连接失败对照。
- 在 /root/cca-bgp/pod.yaml 中编写并应用 CiliumBGPAdvertisement cca-pod。标签为 lab=cca-bgp 和 advertise=pod,通告条目只有一个 PodCIDR。pod 路由器应在 RIB 和 FIB 中都有该 PodCIDR,并收到 Pod HTTP 200。FIB 的 protocol 为 bgp,gateway 为 192.0.2.9,dev 为 router。保留 rib 路由器的对照状态。
- 在 /root/cca-bgp/services.yaml 中以 v1 List 保存并应用一个学员地址池与两个服务。CiliumLoadBalancerIPPool cca-student 的 blocks=[{start: 203.0.113.10, stop: 203.0.113.11}],serviceSelector.matchLabels={lab: cca-bgp, pool: student}。Service cca-selected 与 cca-excluded 的 type=LoadBalancer、loadBalancerClass=io.cilium/bgp-control-plane、externalTrafficPolicy=Cluster、selector.app=cca-bgp-web、port 与 targetPort=8080、protocol=TCP。两个服务都添加 lab=cca-bgp、pool=student,publish 分别为 selected、excluded。确认分配到不同 VIP,并保留初始 cca-retire。
- 在 /root/cca-bgp/vip.yaml 中保存并应用 CiliumBGPAdvertisement cca-vip。标签为 lab=cca-bgp、advertise=vip;advertisements 的唯一条目设置 advertisementType=Service、service.addresses=[LoadBalancerIP]、selector.matchLabels.publish=selected。vip 路由器只能在 RIB/FIB 中拥有 selected 的准确 /32,并返回 200。访问 excluded 和直接访问 Pod 都应失败。
- 读取初始资料 /opt/fixtures/cca-bgp/baseline.json 中的通告 UID、服务 UID 和真实初始 200。在 /root/cca-bgp/withdrawal.json 中记录 advertisement=cca-withdraw、advertisement_uid=初始通告 UID、service=cca-retire、service_uid=初始服务 UID、action=delete-advertisement。只删除 CiliumBGPAdvertisement cca-withdraw。cca-retire 服务、HTTP Pod 和 withdraw peer 必须保留,withdraw 路由器中的 203.0.113.20/32 RIB/FIB 路由应消失且连接失败。
- 将观测工具 report 结果保存到 /root/cca-bgp/report.json,并自行判断和填写 diagnoses:empty 为 no-advertisement,rib 为 not-installed,pod 为 pod-forwarding,vip 为 selected-vip,withdraw 为 withdrawn。读取当前 UID、spec 哈希、RIB/FIB、各请求标识符和服务器响应,说明判断依据。不要把不同请求复制成同一标识符。总评分时,前面所有步骤也必须在当前状态下通过。
提示
- 观测工具:python3 /opt/fixtures/cca-bgp/runtime.py observe 阶段名。阶段名为 inventory、peer、rib、pod、ipam、vip、withdraw、report。
- FRR:ip netns exec cca-rib vtysh -N cca-rib -c 'show bgp ipv4 unicast json'
- FIB:ip -n cca-rib -j route show。其他对照请把名称中的 rib 换成相应名称。
- peer:cilium bgp peers。通告:kubectl get ciliumbgpadvertisement -o yaml。
- 文件应写成单个 JSON/YAML 对象。多个资源请使用 v1 List.items。
- curl 7/000 表示连接失败,000 不是服务器 HTTP 状态码。
记录真实服务器与五个网络的身份
将观测工具 inventory 输出保存到 /root/cca-bgp/inventory.json。读取 Pod 与 CiliumNode 的名称和 UID、真实 Pod IP、已分配 PodCIDR,以及 5 个路由器的 netns、两端 IP 和 AS。不要用整个 10.42.0.0/16 代替节点分配范围。
确认真实 Pod IP 位于哪个节点 PodCIDR。inventory 不会修改配置。
只修正一个 AS,建立无通告连接
读取初始 CiliumBGPClusterConfig cca-bgp,将修改版本保存到 /root/cca-bgp/peers.yaml 并应用。保留 nodeSelector 的 kubernetes.io/os=linux、实例名 cca 和 localASN=65001。只把 empty peer 错误的 peerASN=65003 改为 65002。保留包括 rib、pod、vip、withdraw 在内的 5 个 peer,以及 peerAddress、peerConfigRef。empty 应为 Established,但没有目的通告,Pod 连接应失败。
Cilium 的 peerASN 是对端 FRR 的 AS。peer 会话和通告是两回事,不要为 empty 添加通告。
学到路由但不转发的路由器
在 /root/cca-bgp/rib.yaml 中编写并应用 CiliumBGPAdvertisement cca-rib。标签为 lab=cca-bgp 和 advertise=rib,spec.advertisements 只含一个 advertisementType=PodCIDR 条目。rib 路由器应在 RIB 中有真实节点 PodCIDR 的有效最优 BGP 路由,但 FIB 中没有。保留 FRR 初始 bgp no-rib,并与 Pod HTTP 连接失败对照。
检查 FRR 的 RIB 后,再单独读取 ip -n cca-rib route。本步骤的连接失败是预期对照。
用同一 PodCIDR 验证真实 HTTP 转发
在 /root/cca-bgp/pod.yaml 中编写并应用 CiliumBGPAdvertisement cca-pod。标签为 lab=cca-bgp 和 advertise=pod,通告条目只有一个 PodCIDR。pod 路由器应在 RIB 和 FIB 中都有该 PodCIDR,并收到 Pod HTTP 200。FIB 的 protocol 为 bgp,gateway 为 192.0.2.9,dev 为 router。保留 rib 路由器的对照状态。
不要用静态路由或默认路由绕过。还要确认是谁安装路由,以及真实下一跳是谁。
分离服务地址分配与通告
在 /root/cca-bgp/services.yaml 中以 v1 List 保存并应用一个学员地址池与两个服务。CiliumLoadBalancerIPPool cca-student 的 blocks=[{start: 203.0.113.10, stop: 203.0.113.11}],serviceSelector.matchLabels={lab: cca-bgp, pool: student}。Service cca-selected 与 cca-excluded 的 type=LoadBalancer、loadBalancerClass=io.cilium/bgp-control-plane、externalTrafficPolicy=Cluster、selector.app=cca-bgp-web、port 与 targetPort=8080、protocol=TCP。两个服务都添加 lab=cca-bgp、pool=student,publish 分别为 selected、excluded。确认分配到不同 VIP,并保留初始 cca-retire。
获得地址不代表路由器已经学到该地址。先读取 LoadBalancer status。
只通告相同服务器中选定的 VIP
在 /root/cca-bgp/vip.yaml 中保存并应用 CiliumBGPAdvertisement cca-vip。标签为 lab=cca-bgp、advertise=vip;advertisements 的唯一条目设置 advertisementType=Service、service.addresses=[LoadBalancerIP]、selector.matchLabels.publish=selected。vip 路由器只能在 RIB/FIB 中拥有 selected 的准确 /32,并返回 200。访问 excluded 和直接访问 Pod 都应失败。
PeerConfig 选择通告的标签,与通告选择服务的标签是不同选择器。也要确认应失败的对照。
保留服务,只撤回路由
读取初始资料 /opt/fixtures/cca-bgp/baseline.json 中的通告 UID、服务 UID 和真实初始 200。在 /root/cca-bgp/withdrawal.json 中记录 advertisement=cca-withdraw、advertisement_uid=初始通告 UID、service=cca-retire、service_uid=初始服务 UID、action=delete-advertisement。只删除 CiliumBGPAdvertisement cca-withdraw。cca-retire 服务、HTTP Pod 和 withdraw peer 必须保留,withdraw 路由器中的 203.0.113.20/32 RIB/FIB 路由应消失且连接失败。
删除服务器或 BGP peer 所造成的失败,不能证明通告已撤回。请确认初始 UID 得到保留。
用五种当前状态完成综合事故报告
将观测工具 report 结果保存到 /root/cca-bgp/report.json,并自行判断和填写 diagnoses:empty 为 no-advertisement,rib 为 not-installed,pod 为 pod-forwarding,vip 为 selected-vip,withdraw 为 withdrawn。读取当前 UID、spec 哈希、RIB/FIB、各请求标识符和服务器响应,说明判断依据。不要把不同请求复制成同一标识符。总评分时,前面所有步骤也必须在当前状态下通过。
不要只看报告中的 200,还要确认观测的是哪个地址、哪个请求以及哪个资源生命周期。