k8s实践:Cilium集群下线节点导致其它节点容器网络不通

背景

生产环境内部使用的一个k8s集群,使用Cilium CNI开启BGP与网络设备打通了Pod网段的路由,以满足需要在集群外部通过Pod IP访问Pod服务的需求,正常使用了一段时间以后因为这个集群负载较低需要下线部分节点到其他集群,下线node1节点后发现master2节点上的Pod与集群外网络无法互通,master1和master3节点上Pod网络都正常。

集群配置如下:

# kubectl  get node -owide
NAME      STATUS                     ROLES                  AGE    VERSION    INTERNAL-IP   EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION             CONTAINER-RUNTIME
master1   Ready                      control-plane,master   376d   v1.22.10   10.4.94.32    <none>        Ubuntu 18.04.6 LTS   5.10.0-051000   containerd://1.6.8
master2   Ready                      control-plane,master   376d   v1.22.10   10.4.94.21    <none>        Ubuntu 18.04.6 LTS   5.10.0-051000   containerd://1.6.8
master3   Ready                      control-plane,master   376d   v1.22.10   10.4.94.31    <none>        Ubuntu 18.04.6 LTS   5.10.0-051000   containerd://1.6.8
node1     Ready                      control-plane,master   376d   v1.22.10   10.4.94.23    <none>        Ubuntu 18.04.6 LTS   5.10.0-051000   containerd://1.6.8

# helm -n kube-system list
NAME          	NAMESPACE  	REVISION	UPDATED                                	STATUS  	CHART               	APP VERSION
cilium        	kube-system	3       	2022-12-28 17:18:33.518302411 +0800 CST	deployed	cilium-1.11.9       	1.11.9

# kubectl -n kube-system exec -it cilium-z486s bash
root@l004094032:/home/cilium# cilium status
KVStore:                Ok   Disabled
Kubernetes:             Ok   1.22 (v1.22.10) [linux/amd64]
Kubernetes APIs:        ["cilium/v2::CiliumClusterwideNetworkPolicy", "cilium/v2::CiliumEndpoint", "cilium/v2::CiliumNetworkPolicy", "cilium/v2::CiliumNode", "core/v1::Namespace", "core/v1::Node", "core/v1::Pods", "core/v1::Service", "discovery/v1::EndpointSlice", "networking.k8s.io/v1::NetworkPolicy"]
KubeProxyReplacement:   Strict   [bond0 10.4.94.32 (Direct Routing)]
Host firewall:          Disabled
Cilium:                 Ok   1.11.9 (v1.11.9-4409e95)
NodeMonitor:            Listening for events on 48 CPUs with 64x4096 of shared memory
Cilium health daemon:   Ok
IPAM:                   IPv4: 16/254 allocated from 10.5.113.0/24,
BandwidthManager:       Disabled
Host Routing:           BPF
Masquerading:           Disabled
Controller Status:      75/75 healthy
Proxy Status:           OK, ip 10.5.113.75, 0 redirects active on ports 10000-20000
Hubble:                 Ok   Current/Max Flows: 4095/4095 (100.00%), Flows/s: 38.78   Metrics: Disabled
Encryption:             Disabled
Cluster health:         4/4 reachable   (2023-10-11T02:06:57Z)

root@l004094032:/home/cilium# cilium node list
Name      IPv4 Address   Endpoint CIDR   IPv6 Address   Endpoint CIDR
master1   10.4.94.32     10.5.113.0/24
master2   10.4.94.21     10.5.115.0/24
master3   10.4.94.31     10.5.114.0/24
node1     10.4.94.23     10.5.112.0/24

BGP配置如下:

问题定位

下线node1节点以后master2节点上的pod不能访问集群外部网络,外部网络也无法访问该节点上的pod;从master2节点上IP为10.5.115.93的Pod内ping集群外部IP 10.9.25.120,分别在master2宿主机和10.9.25.120机器上抓包如下所示:

联系网络同事查看网络设备上收到的三台节点的BGP路由信息如下:

通过以上路由表信息发现三个问题:

  1. 每个Cilium节点宣告给网络设备的网段不一定是本节点的容器网段;

  2. node1节点下线后网络设备上的所有的bgp路由信息没有重新宣告,导致网络设备上没有收到master2节点上pod网段10.5.115.0/24的路由信息;

  3. 重启完所有cilium-agent pod以及宿主机节点以后,残留在网络设备上的已经下线节点node1节点上的路由信息10.5.112.0/24,始终没有发生更新。

猜想1:每个cilium-agent宣告给网络设备的路由信息保留在本地配置文件或者etcd里面;

结果:查找了cilium-Sagent挂在的所有配置文件以及etcd都没有发现相关信息

源码追踪

这里主要分析Cilium 1.11.9分支实现BGP网络路由协议相关功能

Cilium启动流程简单梳理,源码如下

bgpSpeaker控制器

控制器初始化及启动

handler方法实现

这里主要分析一下Add事件的处理逻辑,其它事件处理逻辑类似。

这里主要关注podCIDRs如何获取的,通过podCIDRs函数逻辑可知队列中podCIDRs字段是从k8s Node资源的Spec.PodCIDRs字段获取的。

控制器运行逻辑

控制器主要逻辑包含:消费队列中的事件数据、判断是否为节点类型事件、宣告当前节点PodCIDR信息

结论

通过上面源码我们发现Cilium向网络设备宣告的BGP路由信息是从k8s Node资源的Spec.PodCIDRs获取的,这也解释了前面我们发现的三个问题。

以下是k8s集群所有节点PodCIDRs和Cilium实际给每个节点分配的Pod CIDR:

从上面信息我们终于发现了问题原因,导致网络设备上每个k8s节点宣告的路由信息与该节点实际pod网段不一致的原因是因为k8s Node上的PodCIDRs字段与Cilium给每个节点分配的PodCIDRs不一致。

关于为什么k8s Node上设置的PodCIDRs字段与Cilium给每个节点分配的PodCIDRs不一致,我们后续再继续排查。

Last updated