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时走三层网络)