0%

K8S问题排查-概率出现Pod发送ping v6报文no response found问题

问题现象

K8S集群内的一个Pod服务定时发起icmpv6ping报文到集群外的设备,偶现请求无响应应。

原因分析

抓包分析

先在节点上和Pod所在网卡上抓包,分析确认,请求包在节点上有响应,但未进入Pod内,初步判断请求是在节点发往Pod内的过程中丢了。

网卡是否丢包

查看集群上的网卡配置,环境使用的是bound网卡:

1
2
3
4
5
6
7
8
9
10
[root@node1 ~]# ifconfig bound0
bound0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST,MASTER> mtu 1500
inet xx.xx.xx.xx netmask 255.255.0.0 broadcast xx.xx.255.255
inet6 xxxx::xxx:xxxx:xxxx:xxxx prefixlen 64 scopeid 0x20<link>
inet6 xx.xx.xx.xx prefixlen 64 scopeid 0x0<global>
ether xx:xx:xx:xx:xx:xx txqueuelen 1000 (Ethernet)
RX packets 94617918 bytes 39566668050 (36.8 GiB)
RX errors 0 dropped 5011121212 overruns 0 frame 0
TX packets 58685914 bytes 77971464576 (72.6 GiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

查看到RXdrop报文数量很大,且不断增加。考虑到早期出现过bound配置导致的丢包问题,排查相关配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[root@node1 ~]# cat /sys/class/net/bondo/bonding/mode
802.3ad 4

[root@node1 ~]# cat /proc/net/bonding/bond0
Ethernet Channel Bonding Driver: v3.7.1 (April 27, 2011)
Bonding Mode: IEEE 802. 3ad Dynamic link aggregation
Transmit Hash Policy: layer2 (0)
MII Status: up
MII Polling Interval (ms): 100
Up Delay (ms): 0
Down Delay (ms): 0

802.3ad info
LACP rate: slow
Min links: 0
Aggregator selection policy (ad_select): stable
System priority: 65535
System MAC address: 64: 2f: c7: c2: b1: 8b
Active Aggregator Info:
...

MII Status: up
Speed: 10000 Mbps
Duplex: full
Link Failure Count: 1
Permanent Hw addr: 64: 2f: c7: c2: b1: 8b Slave queue ID: 0
Aggregator ID: 1
...

从配置看,Link Failure Count: 1,也就是出现过一次网卡链路问题,看起来跟持续的网络丢包关系不大,从dmesg日志也可以印证这一点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@node1 ~]# dmesg -T |grep bond
[ 7 6 17:52:08 2023]bonding: bondo is being created...
[ 7 6 17:52:08 2023]bonding: bondo already exists
[ 7 6 17:52:08 2023]IPv6: ADDRCONF (NETDEV_UP): bondo: link is not ready
[ 7 6 17:52:08 2023]bondo: Enslaving ens3fo as a backup interface with a down link
[ 7 6 17:52:09 2023]bondo: Enslaving ens1fo as a backup interface with a down link
[ 7 6 17:52:09 2023]bondo: Warning: No 802. 3ad response from the link partner for any adapters in the bond
[ 7 6 17:52:09 2023]IPV6: ADDRCONF (NETDEV_UP): bondo: link is not ready
[ 7 6 17:52:09 2023]IPv6: ADDRCONF(NETDEV_CHANGE): bondo: link becomes ready
[ 7 6 17:52:09 2023]bondo: link status definitely up for interface ens3f0, 10000 Mbps full duplex
[ 7 6 17:52:09 2023]bondo: first active interface up!
[ 7 6 17:52:09 2023] bondo: link status definitely up for interface ens1f0, 10000 Mbps full duplex
...
[ 3 21 01:20:53 2024]bondo: link status definitely down for interface ens3f0, disabling it
[ 3 21 01:24:18 2024]bondo: link status definitely up for interface ens3f0, 10000 Mbps full duduplex
...

继续看抓包结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
节点上抓包结果:
45906 2024-05-08 08:33:19.680488 1000:ff00::1:212 1000:ff00::101 ICMPv6 94 Echo (ping) request id-0xef02, seq=1 (reply in 45911)
45911 2024-05-08 08:33:19.681123 1000:ff00:101 1000:ff00::1:212 ICMPv6 94 Echo (ping) reply id=0xef02, seq=1 (request in 45906)

45917 2024-05-08 08:33:23.640357 1000:ff00::1:212 1000:ff00:101 ICMPv6 94 Echo (ping) request id=0xef02, seq=1 (reply in 45921)
45921 2024-05-08 08:33:23.650087 1000:ff00:101 1000:ff00::1:212 ICMPv6 94 Echo (ping) reply id=0xef02, seq=1 (request in 45917)

45923 2024-05-08 08:33:24.652114 1000:ff00::1:212 1000:ff00::101 ICMPv6 94 Echo (ping) request id=0xef02, seq=1 (reply in 45924)
45924 2024-05-08 08:33:24.654495 1000:ff00::101 1000:ff00::1:212 ICMPv6 94 Echo (ping) reply id=0xef02, seq=1 (request in 45923)

45925 2024-05-08 08:33:26.653971 1000:ff00::1:212 1000:ff00::101 ICMPv6 94 Echo (ping) request id=0xef02, seq=1 (reply in 45926)
45926 2024-05-08 08:33:26.660779 1000:ff00::101 1000:ff00:1:212 ICMPv6 94 Echo (ping) reply id=0xef02, seq=1 (request in 45925)

Pod网卡抓包结果:
38001 2024-05-08 08:33:23.640134 fd00:7a23::466 1000:ff00::101 ICMPv6 94 Echo (ping) id=0xef02 (no response found! )
38004 2024-05-08 08:33:24.652076 fd00:7a23::466 1000:ff00::101 ICMPv6 94 Echo (ping) id=0xef02 (no response found! )
38005 2024-05-08 08:33:26.653936 fd00:7a23::466 1000:ff00::101 ICMPv6 94 Echo (ping) id=0xef02 (no response found! )

对比发现,Pod内是发了3个请求包,均没有响应,跟业务的请求配置2s超时 + 重试3次吻合。但从节点的角度看有4个请求和响应包,且从时间看,是从第2个包开始对应的。

由此怀疑,第1个请求响应包是别的服务触发的,跟现场了解到确实存在两个服务ping设备,且这个请求使用的id0xef2,跟后面3个请求包的id是相同的,初步判断是id相同引起的后续包无法响应。

icmpv6相关资料[1],没有明确的官方文档可以证明id相同的两个ping报文存在问题,从一些个人总结资料[2]里看,是不允许相同的。为了确认是否有问题,在家里使用跟业务类似的c++程序模拟ping设备,构造两个容器内使用相同的id请求集群外的ip地址,可以稳定复现该问题。而同时测试两个系统原生ping命令,未复现该问题。

分析两次复现的抓包结果,并查找相关资料[3],可以解释两种结果的差异原因:

1)为什么c++实现的ping有问题? –ping报文使用的id号的实现是顺序累加,当请求不通时,该程序会重试,且重试的报文依然使用相同的id号,这就导致一个id号冲突必然会导致重试也不通,直到下个轮询里使用新的id号探测恢复

2)为什么原生ping没有问题? –ping报文使用的id号是通过ping的进程id和一个十六进制的与计算得到的,每次独立的ping操作会使用一个计算得到的随机id作为icmp报文的id

id相同为什么会有问题呢?到底是哪里的机制影响了请求的响应?通过家里不断构造场景测试,问题原因和几个疑问的分析结论如下:

问题原因:icmpid相同导致系统记录的conntrack表项无法区分出两个不同的响应包该回给谁,如下所示,2ping请求,一个在节点上,一个在容器内,2ping请求使用了相同的id,这会导致两个ping请求均匹配到第一条表项,进而导致容器内的ping请求得不到响应:

1
2
3
4
[root@node1 ~]# cat /proc/net/nf_conntrack|grep icmpv6
ipv6 10 icmpv6 58 29 src=1000:0000:0000:0000:0000:0000:0212:0165dst=1000:0000:0000:0000:0000:0000:0212:0160 type=128 code=0 id=14640src=1000:0000:0000:0000:0000:0000:0212:0160 dst=1000:0000:0000:0000:0000:0000:0212:0165 type=129 code=0 id=0 mark=0 zone=0 use=2

ipv6 10 icmpv6 58 29 src=fd00:0111:0111:0000:0c11:b42f:f17e:a683dst=1000:0000:0000:0000:0000:0000:0212:0160 type=128 code=0 id=14640src=1000:0000:0000:0000:0000:0000:0212:0160 dst=1000:0000:0000:0000:0000:0000:0212:0165 type=129 code=0 id=14640 mark=0 zone=0 use=2

问题1:为什么节点上两个ping使用同一个id没问题?

因为请求和响应都在节点上,记录的conntrack表项是同一条,且id也相同,所以即使请求和响应不对应,两个请求方都可以得到响应。

1
ipv6   10 icmpv6  58 29 src=1000:0000:0000:0000:0000:0000:0212:0165 dst=1000:0000:0000:0000:0000:0000:0212:0160 type=128 code=0 id=14640 src=1000:0000:0000:0000:0000:0000:0212:0160 dst=1000:0000:0000:0000:0000:0000:0212:0165 type=129 code=0 id=0 mark=0 zone=0 use=2

问题2:为什么一个节点一个容器ping同一个id才有问题?

无必然关系,只要是出集群的请求 + nat转换 + ping id相同,都会存在这个问题,而nat转换是容器出集群依赖的必要机制。非容器场景如果使用了nat机制,理论上同样会出现这个问题。

问题3: 为什么使用不同的id发请求没问题?

在请求源ip,目标ip相同的情况下,不同的id请求会在conntrack表项会新增id不同的记录,请求的响应可以依据id做区分,并正常响应:

1
2
3
4
5
[root@node1 ~]# cat /proc/net/nf_conntrack|grep icmpv6

ipv6 10 icmpv6 58 29 src=fd00:0111:0111:0000:0c11:b42f:f17e:a683 dst=1000:0000:0000:0000:0000:0000:0212:0160 type=128 code=0 id=14640src=1000:0000:0000:0000:0000:0000:0212:0160 dst=1000:0000:0000:0000:0000:0000:0212:0165 type=129 code=0 id=14640 mark=0 zone=0 use=2

ipv6 10 icmpv6 58 29 src=fd00:0111:0111:0000:0c11:b42f:f17e:a683 dst=1000:0000:0000:0000:0000:0000:0212:0160 type=128 code=0 id=53764src=1000:0000:0000:0000:0000:0000:0212:0160 dst=1000:0000:0000:0000:0000:0000:0212:0165 type=129 code=0 id=53764 mark=0 zone=0 use=2

问题4:使用相同id请求,异常会持续多久?

由表项老化时间决定,默认是30s

解决方案

  1. 业务侧重试的报文不使用相同的id号。
  2. 同一个环境下避免多个业务同时ping相同的设备,或规划使用不同的id号,避免冲突。

参考资料

https://datatracker.ietf.org/doc/html/rfc4443

https://community.icinga.com/t/how-to-avoid-icmp-identifiers-colliding/5290

https://hechao.li/2018/09/27/How-Is-Ping-Deduplexed/