一、现象

部署应用时,新建的POD调度到K8S的部分计算节点后,发现ping不通pod,自然服务也不可用

二、分析

2.1 查看网络信息

进入到有问题的节点

docker_id=`docker ps | grep cluster-test| grep POD | awk '{print$1}'` && docker_pid=`docker inspect -f{{.State.Pid}} $docker_id` && nsenter -n -t $docker_pid

查看网络栈信息

4d3803e4fdcf09effae7021a714dac82.png

IP地址和网关设置都正确,但是尝试ping网关10.233.91.0时不通

2.2 抓包

由于容器网络采用的是对网卡形式,即在宿主机上建立一个虚拟网卡,容器中创建虚拟网卡,两个虚拟网卡组成一个对网卡veth,所以我们对宿主机的虚拟网卡进行抓包

fc67ffe2bf64fa74c568738e9deaa5cb.png

在宿主机的对网卡上,可以发现存在ARP请求,但是却没有响应包回去,这个ARP请求试图获取容器网关169.254.1.1的mac地址失败

进一步查看容器的mac地址,发现arp条目的mac信息为incomplete,说明确实没有接收到mac地址

e62d5eb8736b52a36cfed0b5e3818956.png

尝试手动添加mac地址后,发现可以ping通了

ip neigh replace 169.254.1.1 lladdr ee:ee:ee:ee:ee:ee dev eth0

801c2040bf953fd89ce5c0ba1c6685e0.png

中途我们还怀疑防火墙的问题,但是防火墙只针对宿主机外部的流量进行访问限制,而calico虚拟网关与容器网络之间未过墙,所以防火墙应该没有影响

2.3 arp请求未响应的分析

虽然手动可以解决问题,但是实际生产环境中,不可能创建一个POD,就手动添加ARP条目,所以我们还需要继续研究,为什么arp请求未正确响应

经过反复查找相关资料和验证,发现重要信息,就是calico要响应arp请求还需要具备三个条件

1)The host receives an ARP request on an interface which has proxy-ARP enabled.

2)The host knows how to reach the destination

3)The interface that the host would use to reach the destination is not the same one that it received the ARP request on

翻译过来就是

1)  宿主机的arp代理得打开

2)  宿主机需要有访问目的地址的明确路由

3)  发送arp request的接口与接收arp request的接口不能是相同,即容器中的默认网关不能是calico的虚拟网关

我们一步步验证这三点是否都满足

第一步,查看calico网卡的网络内核参数proxy_arp

[root@d0703 ~]# cat/proc/sys/net/ipv4/conf/calieabde1eea72/proxy_arp
1

数字1说明是arp代理开启的

第二步,我们查看默认网关

先看正常节点的默认网关

3977d6b6324164cd7841cf2a2deb08fd.png

然后再看有问题的节点,发现异常

3ed0ab0bc7312e04c51357fd0d7ab608.png

分析发现,虽然destination都是0.0.0.0,但掩码却是255.255.255.255,说明这里的0.0.0.0只是一个主机IP地址,并不是一个网段或者默认网关

这相当于这个计算节点并不存在默认网关,这显然不符合第二个要求

解决办法是,重新添加网关

ip route del 0.0.0.0

route add default gw 172.18.163.254

默认网关添加后,网络立即恢复正常!

最终的原理图是这样的

ae9270980aac471f2bb0022debc25861.png

符合Proxy ARP要求,才返回mac地址

三、结论

1,我们在给宿主机设置默认网关时,少添加了掩码,导致实际添加的只是主机,造成宿主机默认网关的缺失

2,实际排错过程中,应该设计好准确的检索关键词,才能在网上找到有价值的信息

3,虚拟网卡的网络实现与物理网卡还是有区别的,怎么也不会想到宿主机的默认路由与容器的mac会存在什么关联,但是calico的虚拟网卡的逻辑就是这么设计的,而实际虚拟机或者物理机的网络,不设置默认路由没有关系的,有静态路由就够了,现在看来默认路由还是很重要的

4,中途我们还试图放弃查找原因,因为经过反复试验,并且咨询了几位CCIE的专家,实在找不出原因。但是现实是由于K8S集群计算节点较少,剩余的节点如果也莫名其妙出问题,那么容器集群就面临瘫痪了,现实迫使我们继续深入研究。

四、参考链接

https://www.dasblinkenlichten.com/getting-started-with-calico-on-kubernetes/

https://github.com/projectcalico/calico/issues/4186

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐