[故障排查]解决podip Destination Host Unreachable问题
解决podip Destination Host Unreachable问题
问题背景
最近k8s节点扩容,新增其中一个节点,网络出现问题(假设podA为异常节点上的pod):
1.从任何节点(包括负载节点)都无法ping通podA的IP,均出现From xx.xx.xx.xx icmp_seq=x Destination Host Unreachable
错误
2.从podA容器内部可以ping通集群外部IP,但偶尔会出现第一二个响应严重延迟现象
3.各节点之间可以正常ping通
问题分析
首先要知道:
1.网络中的报文不可能凭空丢失,若不通肯定在是哪个环节被丢弃,借此可以通过抓包逐渐缩小范围以此来定位问题。
2.集群使用的网络插件为calico IPIP模式,主机与容器间是如何通信:
(1) 主机与主机间通过tunl0来通信
(2) 主机与容器间通过veth设备通信(一头在容器内为eth0,一头在容器外为calixxxxxxxxx)
(3) 进出容器的报文是通过代理arp实现通信(容器内默认网关固定为169.254.1.1,宿主机充当路由代理arp)
排查思路
1.检查路由,对比新旧节点路由表。
route
、route -n
、ip route
都可以查看路由。
2.请求抓包,查看容器内arp记录。
具体:
(1) 在宿主节点ping podA IP,观察报文去向。
(2) 在宿主节点,route
找到podA对应的网卡(calixxxxxxxxx),通过tcpdump
抓取这个网卡的报文。
报文来到主机,发起arp请求,但一直未得到响应。
tcpdump -i calixxxxxxxxx -vvnnel
18:00:00.122488 ee:ee:ee:ee:ee:ee > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42: Ethernet (len 6), IPv4 (len 4), Request who-has xx.xx.xx.xx tell xx.xx.xx.xx, length 28
18:00:01.154498 ee:ee:ee:ee:ee:ee > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42: Ethernet (len 6), IPv4 (len 4), Request who-has xx.xx.xx.xx tell xx.xx.xx.xx, length 28
18:00:02.178526 ee:ee:ee:ee:ee:ee > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42: Ethernet (len 6), IPv4 (len 4), Request who-has xx.xx.xx.xx tell xx.xx.xx.xx, length 28
...
(3) 进入podA容器,检查ip和网卡信息是否和主机路由对上,有没有arp记录。
容器内网卡和ip都没问题,但没有arp记录。
ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
3: eth0@if14: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1440 qdisc noqueue
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
inet xx.xx.xx.xx/32 scope global eth0
valid_lft forever preferred_lft forever
4: tunl0@NONE: <NOARP> mtu 1480 qdisc noop qlen 1
link/ipip 0.0.0.0 brd 0.0.0.0
arp -a
(4) 主机检查arp记录。
主机查看arp状态为FAILED
, imcomplete
表示无mac地址响应。
arp -a
? (xx.xx.xx.xx) at <incomplete> on calixxxxxxxxx
ip neigh
xx.xx.xx.xx dev calixxxxxxxxx FAILED
(5) 由上面的排查结果看出:ping podIP时发出去的报文通过宿主节点广播尝试获取podA的mac地址,但podA容器却没有响应arp,没有mac地址,报文不知往哪里去,由此被丢弃。
因此,只需要解决容器为何不会响应arp请求这个问题。
通过查阅资料得知:
By enabling proxy-arp on this interface Calico is instructing the host to reply to the ARP request on behalf of someone else that is, through proxy. The rules for proxy-ARP are simple. A host which has proxy-ARP enabled will reply to ARP requests with it’s own MAC address when…
- The host receives an ARP request on an interface which has proxy-ARP enabled.
- The host knows how to reach the destination
- The interface the host would use to reach the destination is not the same one that it received the ARP request on
So in this case, the container is sending an ARP request for 169.254.1.1. Despite this being a link-local address, the host would attempt to route this following it’s default route out the hosts physical interface. This means we’ve met all three requirements so the host will reply to the ARP request with it’s MAC address.
发现要通过arp代理需要满足三个条件:
- 宿主机的arp代理得打开
- 宿主机需要有访问目的地址的明确路由
- 发送arp request的接口与接收arp request的接口不能是相同,即容器中的默认网关不能是calico的虚拟网关
开始检查:
1.检查对应网卡是否开启了arp代理(1为开启)。
cat/proc/sys/net/ipv4/conf/calixxxxxxxxx/proxy_arp
1
2.宿主机需要有访问目的地址的明确路由。
通过route
检查宿主机的默认路由和是否有podA对应的路由
3.进入容器检查默认网关。
以上检查后发现都没问题,但还是不通怎么回事?
最后把目标移向内核参数,linux内核中也有两个与arp相关参数:
- arp_announce: 对网络接口上本地IP地址发出的ARP报文作出相应级别的限制。
0:本机所有IP地址都向任何一个接口通告ARP报文。
1:尽量仅向该网卡回应与该网段匹配的ARP报文。
2:只向该网卡回应与该网段匹配的ARP报文。 - arp_ignore: 定义对目标地址为本地IP的ARP询问不同的应答模式。
0:响应任意网卡上接收到的对本机IP地址的arp请求(包括环回网卡上的地址),而不管该目的IP是否在接收网卡上。
1:只响应目的IP地址为接收网卡上的本地地址的arp请求。
2:只响应目的IP地址为接收网卡上的本地地址的arp请求,并且arp请求的源IP必须和接收网卡同网段。
3:如果ARP请求数据包所请求的IP地址对应的本地地址其作用域(scope)为主机(host),则不回应ARP响应数据包,如果作用域为全局(global)或链路(link),则回应ARP响应数据包。
4~7:预留。
8:不回应所有的arp请求。
果断检查下异常节点的内核参数:
sysctl net.ipv4.conf.all.arp_announce
0
sysctl net.ipv4.conf.all.arp_ignore
2
果然,这台异常节点的 net.ipv4.conf.all.arp_ignore=2
!!!
解决
修改/etc/sysctl.conf
里的net.ipv4.conf.all.arp_ignore=0
然后sysctl -p
刷新到内存。
ps: arp_ignore和arp_announce参数分别有all,default,lo,eth0等对应不同网卡。当all和具体网卡的参数值不一致时,配置为较大值的生效。一般只需修改all和某个具体网卡的参数即可。
至此,问题解决。