记一次kubernetes v1.18.7 ingress访问异常问题及解决

安装kubenetes 1.18.7 高可用集群后,一次pod异常重启后,由于iptables规则失效, 在集群内访问ingress pod失败, 这篇文章仅记录处理问题过程

post thumb
Kubernetes
作者 Louis 发表于 2020年12月15日

[TOC]

安装kubenetes1.18.7集群后,一次异常重启后, 在集群内访问ingress失败, 这篇文章仅记录处理问题过程。

kubernetes集群搭建

  • 系统环境: Ubuntu 18.04.
主机名 IP地址
master0 192.168.0.118
master1 192.168.0.119
master2 192.168.0.26
server22 192.168.0.20
server500 192.168.0.24

我们生产环境, 采用sealos一键快速部署集群.

$ sealos init --master 192.168.0.118 \
	--master 192.168.0.119 \
	--master 192.168.0.26  \
	--node 192.168.0.20 \
	--node 192.168.0.24 \
 	--pkg-url /root/kube1.18.7.tar.gz \
	--version v1.18.7  \
	--passwd ubuntu --user root

ingress是使用官方的nginx-ingress, 默认是daemonst + hostnetwork.

$ kubectl apply -f https://kuboard.cn/install-script/v1.15.2/nginx-ingress.yaml

问题发现,

查看ingress后, 发现server22上面的ingress pod始终无法访问 , 导致对于的宿主机也无法访问其80端口.

image-20201216015142018

root@ubuntu:~# kubectl get pod  -n nginx-ingress -owide
NAME                  READY   STATUS    RESTARTS   AGE   IP             NODE     
nginx-ingress-ndxd9   1/1     Running   0          79m   10.1.117.216   server22 
nginx-ingress-xw5bb   1/1     Running   0          25d   10.1.220.194   server500 

在server22上, 发现一直hang在那里.

$ curl 127.0.0.1

在server500 上

root@ubuntu:~# curl 127.0.0.1
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.17.3</center>
</body>
</html>

排查思路

基于hostNetwork网络实现的对外暴露端口, 其本质就是iptablesDNAT. 一开始业务人员反映是svc访问不了, 导致整个排除进入ipvs的排错. 经过定位, 才发现是宿主机到ingress的pod网络不通.

以下是简便的步骤.

ingress主机是暴露80端口, 所以查找关键字80即可. 这里可以看到, 到pod的网段10.1.117.194的流量全部到CNI-DN-a2617edac93cc96942325这条自定义规则上, 而且生成了三类规则. 其中有两条是重复的, 一条是新的.

$ iptables-save |grep -w 80
-A CNI-DN-0405c966411786b4a6079 -s 10.1.117.194/32 -p tcp -m tcp --dport 80 -j CNI-HOSTPORT-SETMARK
-A CNI-DN-0405c966411786b4a6079 -s 127.0.0.1/32 -p tcp -m tcp --dport 80 -j CNI-HOSTPORT-SETMARK
-A CNI-DN-0405c966411786b4a6079 -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.1.117.194:80
-A CNI-DN-9c176252e9af1b9ec0d79 -s 10.1.117.216/32 -p tcp -m tcp --dport 80 -j CNI-HOSTPORT-SETMARK
-A CNI-DN-9c176252e9af1b9ec0d79 -s 127.0.0.1/32 -p tcp -m tcp --dport 80 -j CNI-HOSTPORT-SETMARK
-A CNI-DN-9c176252e9af1b9ec0d79 -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.1.117.216:80
: 也就是这三条规则. 10.1.117.194 这个ip的pod已经被销毁了, 所以访问注定就不成功
-A CNI-DN-a2617edac93cc96942325 -s 10.1.117.194/32 -p tcp -m tcp --dport 80 -j CNI-HOSTPORT-SETMARK
-A CNI-DN-a2617edac93cc96942325 -s 127.0.0.1/32 -p tcp -m tcp --dport 80 -j CNI-HOSTPORT-SETMARK
-A CNI-DN-a2617edac93cc96942325 -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.1.117.194:80
: 其实真正生效的就是这个规则, iptables的优先匹配.
-A CNI-HOSTPORT-DNAT -p tcp -m comment --comment "dnat name: \"k8s-pod-network\" id: \"67a31caecdf4bd8f176f3935263e4a3b309f56b0f2b25bb05352dc67de463cea\"" -m multiport --dports 80,443 -j CNI-DN-a2617edac93cc96942325
-A CNI-HOSTPORT-DNAT -p tcp -m comment --comment "dnat name: \"k8s-pod-network\" id: \"1305c56a786475d02cec2ddea98d3445bf8329fe6de5ac5adcb203f5932f8bfd\"" -m multiport --dports 80,443 -j CNI-DN-0405c966411786b4a6079
-A CNI-HOSTPORT-DNAT -p tcp -m comment --comment "dnat name: \"k8s-pod-network\" id: \"8b83153a6c417bcf7f5a5f73d1725593c318b6afc807ff93b40f1caf76b21051\"" -m multiport --dports 80,443 -j CNI-DN-9c176252e9af1b9ec0d79

纵观其他主机server500的规则. 只有一条CNI-HOSTPORT-DNAT

-A CNI-HOSTPORT-DNAT -p tcp -m comment --comment "dnat name: \"k8s-pod-network\" id: \"4d3b483f886a775ce60fc3482c308aea1a5ba0b876ca8126a02562cf29ade9a2\"" -m multiport --dports 80,443 -j CNI-DN-4d0339c362ca90c577adb

对比后, 很明显的发现, 10.1.117.194这个是老pod的ip. 应该是这个pod生命周期消失后, iptables规则没有自动去除, 新生成的10.1.117.216pod的iptables规则添加后, 又被覆盖.

解决

知道了问题所在, 那么解决方法也很简单

$ iptables-save > iptables.20201215
## 删除无用的规则.
$ sed -i '/CNI-DN-a2617edac93cc96942325/d' iptables.20201215
$ sed -i '/CNI-DN-0405c966411786b4a6079/d' iptables.20201215
$ iptables-restore < iptables.20201215
上一篇
sealos join master 失败