kubectl get nodes 缓慢问题排查_执行速读慢?

问题描述


最近在某个 k8s 集群其中一个节点 (master1) 上执行 kubectl get nodes 大概需要 45s 的时间才有数据返回,而在另外的 master 上执行同样的命令却是很快返回。

通过 kube-apiserver 的日志来看,是无法连接上 metrics-server,从而导致超时。

进而发现这个 master 无法与其他节点的 flannel.1 的 IP 互相 ping 通。

排查结果


因为我们的网络组件使用的 canal,跨主机通信时,通过 flannel (vxlan)。

除 master1 以外,其他节点的 arp 中 master1 上的 flannel.1 对应的 mac 地址缺失,最后是通过重启 canal 组件解决。

排查过程


环境信息
在这里插入图片描述

注:由于是 master1 有问题,其他节点无问题,因此以下拿 master1 与 master3 进行说明

1. 在 master1 上执行 kubectl get nodes 大概需要 45s,如下:


[root@master1 ~]$ time kubectl get nodes
NAME     STATUS   ROLES    AGE    VERSION
master1   Ready    <none>   100d   v1.14.8
master2   Ready    <none>   100d   v1.14.8
master3   Ready    <none>   100d   v1.14.8
node1     Ready    <none>    100d  v1.14.8
node2     Ready    <none>   100d   v1.14.8
 
real    0m45.0s

同时在 master3 执行 kubectl get nodes,很快返回,如下:

[root@master3 ~]$ time kubectl get nodes
NAME    STATUS   ROLES    AGE    VERSION
master1   Ready    <none>   100d   v1.14.8
master2   Ready    <none>   100d   v1.14.8
master3   Ready    <none>   100d   v1.14.8
node1     Ready    <none>    100d  v1.14.8
node2     Ready    <none>   100d   v1.14.8
 
real    0m0.452s

开始认为是 master1 资源的问题 (也不知道怎么想的),检查了一下,都正常。

2. 因为执行 kubectl 命令会经过 kube-apiserver,于是查看 master1 的 apiserver 的日志,


如下:

E1124 11:40:21.145      1 available_controller.go:353] v1beta1.custom.metrics.k8s.io failed with: Get https://10.68.225.236:443: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
 
E1124 11:40:22.237      1 available_controller.go:353] v1beta1.custom.metrics.k8s.io failed with: Get https://10.68.225.236:443: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
 
E1124 11:40:23.358      1 available_controller.go:353] v1beta1.custom.metrics.k8s.io failed with: Get https://10.68.225.236:443: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
 
E1124 11:40:34.469      1 available_controller.go:353] v1beta1.custom.metrics.k8s.io failed with: Get https://10.68.225.236:443: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)

以上,很明显是无法连接到 metrics。

尝试在 master1 和 master3 上进行 telnet 10.68.225.236 443,结果如下:

master1:

[root@master1 ~]$ telnet 10.68.225.236 443
Trying 10.68.225.236...

master3:

[root@master3 ~]$ telnet 10.68.225.236 443
Trying 10.68.225.236...
Connected to 10.68.225.236.
Escape character is '^]'.

查看 metrics 的 pod 所在节点,如下:

[root@master3 ~]$ kubectl get pod -A -o wide |grep "metric" |awk '{print $1,$2,$7,$8}'
kube-system monitoring-kube-state-metrics-metrics-v1-0-645bc4cb6f-ch5dz 10.68.4.133 node1
kube-system monitoring-metrics-server-server-v1-0-6ff56d4d6d-fk9gd 10.68.3.210 node2
kube-system monitoring-metrics-server-server-v1-0-6ff56d4d6d-n7zgz 10.68.5.192 node3

很显然 metrics 不在 master1 上,也不再 master3 上。

而 master1 不能与之通信,但 master3 可以,说明 master1 跨主机通信时,有问题。

3. canal 在 pod 跨主机通信时,参考 flannel (vxlan) 数据流向,如下图所示:


在这里插入图片描述

整个过程需要封包解包 (这里就不说具体的啦),需要通过主机网络。

尝试去看看 master1 与 master3 的 arp 与 fdb,如下:

master1:

[root@master1 ~]$ ip neigh |grep flannel.1
10.68.1.0 dev flannel.1 lladdr 16:23:8e:ab:c6:5c PERMANENT
10.68.4.0 dev flannel.1 lladdr 82:67:5t:5f:43:3b PERMANENT
10.68.2.0 dev flannel.1 lladdr a2:23:78:a5:7d:de PERMANENT
10.68.3.0 dev flannel.1 lladdr 32:a3:2r:8e:fb:2r PERMANENT
[root@master1 ~]$ bridge  fdb | grep flannel.1
32:a3:2r:8e:fb:2r dev flannel.1 dst 192.168.1.143 self permanent
a2:23:78:a5:7d:de dev flannel.1 dst 192.168.1.141 self permanent
16:23:8e:ab:c6:5c dev flannel.1 dst 192.168.1.142 self permanent
82:67:5t:5f:43:3b dev flannel.1 dst 192.168.1.144 self permanent

master3:

[root@master3 ~]$ ip neigh |grep flannel.1
10.68.0.0 dev flannel.1 INCOMPLETE
10.68.4.0 dev flannel.1 lladdr 82:67:5t:5f:43:3b PERMANENT
10.68.2.0 dev flannel.1 lladdr a2:23:78:a5:7d:de PERMANENT
10.68.3.0 dev flannel.1 lladdr 32:a3:2r:8e:fb:2r PERMANENT
[root@master3 ~]$ bridge  fdb | grep flannel.1
32:a3:2r:8e:fb:2r dev flannel.1 dst 192.168.1.143 self permanent
a2:23:78:a5:7d:de dev flannel.1 dst 192.168.1.141 self permanent
82:67:5t:5f:43:3b dev flannel.1 dst 192.168.1.144 self permanent
36:9u:9c:53:4a:10 dev flannel.1 dst 192.168.1.140 self permanent

由 master3 可知,master1 的 flannel.1 的 mac 地址缺失。

因此认为,master1 上的 pod 与其他节点上的 pod 通信时,数据包无法返回。

也就是说 master1 与其他节点的 flannel.1 的 IP 是不通的。

4. 以上只是猜想,但还是要抓包确认一下。


在 master1 上 ping master3 的 flannel.1 的 IP。

同时,在 master1、master3 上对 eth0、flannel.1 进行抓包,结果如下:

master1:

ping 10.68.1.0

master1 抓包显示:

[root@master1 ~]$ tcpdump -lnni flannel.1 |grep 10.68.1.0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on flannel.1, link-type EN10MB (Ethernet), capture size 262144 bytes
13:24:07.618633 IP 10.68.0.0 > 10.68.1.0: ICMP echo request, id 28296, seq 1, length 64
13:24:08.618726 IP 10.68.0.0 > 10.68.1.0: ICMP echo request, id 28296, seq 2, length 64
13:24:09.618719 IP 10.68.0.0 > 10.68.1.0: ICMP echo request, id 28296, seq 3, length 64
13:24:10.618710 IP 10.68.0.0 > 10.68.1.0: ICMP echo request, id 28296, seq 4, length 64
13:24:11.618723 IP 10.68.0.0 > 10.68.1.0: ICMP echo request, id 28296, seq 5, length 64
 
[root@master1 ~]$ tcpdump -lnni eth0 |grep 10.68.1.0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
IP 10.68.0.0 > 10.68.1.0: ICMP echo request, id 25177, seq 1, length 64
IP 10.68.0.0 > 10.68.1.0: ICMP echo request, id 25177, seq 2, length 64
IP 10.68.0.0 > 10.68.1.0: ICMP echo request, id 25177, seq 3, length 64
IP 10.68.0.0 > 10.68.1.0: ICMP echo request, id 25177, seq 4, length 64
IP 10.68.0.0 > 10.68.1.0: ICMP echo request, id 25177, seq 5, length 64

master3 抓包显示:

[root@master3 ~]$ tcpdump  -lnni eth0 |grep 10.68.0.0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
IP 10.68.0.0 > 10.68.1.0: ICMP echo request, id 30689, seq 1, length 64
IP 10.68.0.0 > 10.68.1.0: ICMP echo request, id 30689, seq 2, length 64
IP 10.68.0.0 > 10.68.1.0: ICMP echo request, id 30689, seq 3, length 64
IP 10.68.0.0 > 10.68.1.0: ICMP echo request, id 30689, seq 4, length 64
IP 10.68.0.0 > 10.68.1.0: ICMP echo request, id 30689, seq 5, length 64
 
[root@master3 ~]$ tcpdump  -lnni flannel.1 |grep 10.68.0.0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
IP 10.68.0.0 > 10.68.1.0: ICMP echo request, id 30689, seq 1, length 64
ARP, Request who-has 10.68.0.0 tell 10.68.1.0, length 28
IP 10.68.0.0 > 10.68.1.0: ICMP echo request, id 30689, seq 2, length 64
ARP, Request who-has 10.68.0.0 tell 10.68.1.0, length 28
IP 10.68.0.0 > 10.68.1.0: ICMP echo request, id 30689, seq 3, length 64
ARP, Request who-has 10.68.0.0 tell 10.68.1.0, length 28
IP 10.68.0.0 > 10.68.1.0: ICMP echo request, id 30689, seq 4, length 64
ARP, Request who-has 10.68.0.0 tell 10.68.1.0, length 28
IP 10.68.0.0 > 10.68.1.0: ICMP echo request, id 30689, seq 5, length 64

由以上可知,在 master1,ping master3 的 flannel.1 的 IP 时,数据包已经到了 master3 的 flannel.1,但是因为 mac 信息无法获取,所以数据包无法返回。

5. 由以上可知,除 master1 以外的其他节点的 arp 中缺少了 master1 的 flannel.1 的 mac 地址,导致数据包无法返回。


而跨主机通信时,通过 flannel,而负责维护这些信息的是 flanneld。

所以只需要重启一下 canal 即可重新刷新相关信息。

6. 重启除 master1 以外节点的 canal


kubectl delete po -n kube-system canal-xxx

7. 查看 master3 的 arp 与 fdb


[root@master3 ~]$ ip neigh |grep flannel.1
10.68.0.0 dev flannel.1 lladdr 36:9u:9c:53:4a:10 PERMANENT
10.68.4.0 dev flannel.1 lladdr 82:67:5t:5f:43:3b PERMANENT
10.68.2.0 dev flannel.1 lladdr a2:23:78:a5:7d:de PERMANENT
10.68.3.0 dev flannel.1 lladdr 32:a3:2r:8e:fb:2r PERMANENT
[root@master3 ~]$ bridge  fdb | grep flannel.1
32:a3:2r:8e:fb:2r dev flannel.1 dst 192.168.1.143 self permanent
a2:23:78:a5:7d:de dev flannel.1 dst 192.168.1.141 self permanent
82:67:5t:5f:43:3b dev flannel.1 dst 192.168.1.144 self permanent
36:9u:9c:53:4a:10 dev flannel.1 dst 192.168.1.140 self permanent

8. 在 master1 上执行 kubectl get nodes


[root@master1 ~]$ time kubectl get nodes
NAME    STATUS   ROLES    AGE    VERSION
master1   Ready    <none>   100d   v1.14.8
master2   Ready    <none>   100d   v1.14.8
master3   Ready    <none>   100d   v1.14.8
node1     Ready    <none>   100d   v1.14.8
node2     Ready    <none>   100d   v1.14.8
 
real    0m0.538s
user    0m0.153s
sys     0m0.104s

版权声明:本文为作者原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原创文章,作者:老C,如若转载,请注明出处:https://www.code404.icu/1278.html

发表评论

登录后才能评论