hello云胜

技术与生活

0%

解决一个calico网络pod内ping不通问题

问题

遇到一个问题,有用户发现自己的应用无法调用一个集群外的服务。目标服务ip是100.125.1.xx

在容器内ping测试,发现直接ping不通。

在node节点上ping测试,发现可以ping通。

通过tcpdump进行抓包进行分析

根据calico的网络原理,可知。pod的流程会通过pod内的veth-peer转到node上对应的calixxxx网卡上

先说说怎么找容器和node上上成对的网卡

image-20240801152920925

看到容器内部id为4的网卡,后面对应了3268

那么你在对应的node节点上,就会找到对应的id为3269的网卡

image-20240801153058353

对calixxxx网卡进行抓包

1
tcpdump -i calixxxx host 100.125.1.xx

image-20240801151955916

没有收到响应。

按理说,calixxxx网卡会把流量交给eth0发出去

继续对eth0网卡抓包

1
tcpdump -i eth0 host 100.125.1.xx

image-20240801151957398

发现也没有收到响应

在node上ping,同时抓包

image-20240731170022167

发现是正常。

对比两个报文。注意到正常的报文source是node节点的ip,而从pod内ping的报文,sourceip还是pod的ip。这不对啊。

这响应报文肯定回不来了。

为什么会这样

按理说出去的podip应该进行snat,而snat是由iptables负责的。

赶紧去查看iptables规则

1
iptabls -t nat -L

发现最下面有这么一条

1
2
3
Chain cali-nat-outgoing (1 references)
target prot opt source destination
MASQUERADE all -- anywhere anywhere /* cali:Dw4T8UWPnCLxRJiI */ match-set cali40masq-ipam-pools src ! match-set cali40all-ipam-pools dst

看到这条规则,豁然开朗。这条规则的意思是

1
2
对 源IP是calico地址池内的,并且 目的ip不是calico地址池内的流量。要就行nat转换
也就是说,k8s集群内的pod访问外部ip的时候,出去的流量会进行snat转换,集群内pod互相访问不需要进行nat转换

这是非常合理的,问题出就出来我这里要访问的外部ip,它匹配了我的pod网段。。。

cali40masq-ipam-pools也就是我们calico网段的配置

1
2
3
4
5
6
7
8
9
10
kubectl -n kube-system get ippool default-ipv4-ippool  -oyaml
...
spec:
blockSize: 26
cidr: 100.64.0.0/10
ipipMode: Always
natOutgoing: true
nodeSelector: all()
vxlanMode: Never
...

也可以去ipset里查看这个cali40masq-ipam-pools

1
ipset list

所以,当我们在pod内ping的时候,源ip在100.64.0.0/10这个网段,并且更关键的是目的ip也在这个网段里了,所以不进行nat转换。podip原样出去了,因为podip在k8s集群之外并没有对应的路由规则,所以目的服务器返回的包,肯定是回不来的。所以我们这边收不到响应。

所以这个问题的关键就是,外部服务的ip段和我们配的容器ip段有重叠。