记一次pod无法通过clusterIP访问同主机其它pod的排障过程

Saturday, March 30, 2019

kubernetes:v1.12.4
docker:18.06.1-ce
flannel:v0.10.0-amd64,模式:ali-vpc
CoreDNS:1.2.2

线上环境服务(k8s集群自建在阿里云)偶尔报故障,排除时发现某个node节点上的一个服务器有时会出现解析不了redis的域名的情况,无法连上redis。
进一步排除发现:该节点上的pod无法通过clusterIP访问同主机的pod,但能通过clusterIP访问其它主机的pod。

感觉是kube-proxy生成iptables规则出了问题,查看iptables规则列表,一切正常。
在问题node节点上的一个pod做域名解析的操作,在node节点上抓包看了一下:

IP10.10.1.32是做域名解析测试的podIP,10.68.0.2是集群DNS的IP地址。

tcpdump  -n -i cni0 host 10.10.1.32
21:26:47.783674 IP 10.10.1.32.51321 > 10.68.0.2.domain: 21117+ A? www.baidu.com.default.svc.cluster.local. (57)
21:26:47.783737 IP 10.10.1.32.51321 > 10.68.0.2.domain: 21596+ AAAA? www.baidu.com.default.svc.cluster.local. (57)

我们可用看到请求是发送给DNS的clusterIP10.68.0.2正常情况下应该是netfilter做了目标IP的DNAT转换,请求应该是直接发给DNS的podIP,比如DNS的podIP是10.10.1.50,应该是10.10.1.32 > 10.10.1.50才对。
如果DNSpod是同主机的,就是DNS的podIP作为源IP直接返回,如果是请求发给不同主机的DNSpod,那么返回到本机时netfilter会做SNAT处理,替换源IP位10.68.0.2。 继续抓包发现请求能正常打到不同主机的DNSpod时,也就是说在访问目标是别的主机的podIP时候,netfilter能对clusterIP做DNAT转换成podIP,访问目标是同主机的podIP时,netfilter并没有做DNAT转换,直接将请求发给clusterIP了。

那么问题还是回到iptables规则问题上来了。 查看kube-proxy日志:

kube-proxy: I0324  server_others.go:148] Using iptables Proxier.
kube-proxy: W0324  proxier.go:304] missing br-netfilter module or unset sysctl br-nf-call-iptables; proxy may not work as intended  15807 server_others.go:178] Tearing down inactive rules.

居然没有开启内核配置br-nf-call-iptables……

找到问题了,开启bridge-nf-call-iptables解决

echo '1' > /proc/sys/net/bridge/bridge-nf-call-iptables

bridge-nf-call-iptables的作用

当bridge-nf-call-iptables开启时,在二层网桥转发的数据也会被iptables链进制规则限制,而同主机的pod直接的数据转发是直接通过网桥进行转发的,而网桥在二层网络进行数据处理,所以bridge-nf-call-iptables没有开启时,pod无法通过clusterIP访问同主机的pod,但能通过clusterIP访问其它主机的pod(访问不同主机的pod时走三层网络)