关于kubernetes:记一次k8s网络故障排查与学习

52次阅读

共计 4436 个字符,预计需要花费 12 分钟才能阅读完成。

背景形容

  8.25 上午 10 点 55 分左右,业务反馈测试环境容器平台无法访问,11 点 17 分左右服务复原,查问网关日志,发现容器服务呈现大量 504:

  网关上游是容器集群 ingress,ingress 谬误日志有什么线索吗?

  局部业务存在常态化超时状况,临时排除再外不关注。剖析域名发现,不止容器服务超时,还有其余几个服务存在超时景象,谬误日志显示是在建设连贯阶段就超时了(”while connecting to upstream”)。

  为什么这些服务忽然大量超时呢?难道是 ingress 异样了?

  另外,同一时刻还发现间接在节点上执行 kubectl 命令响应也十分慢,apiserver 服务为什么会这么慢呢?依赖的 etcd 或者本身异样了?容器平台也强依赖 apiserver 服务,是 apiserver 的慢导致的容器平台超时吗?那其余几个服务怎么解释呢?

初步排查

  既然 kubectl 命令响应都十分慢,那先看看 apiserver 的监控以及日志吧。发现 apiserver 根本指标 cpu、内存、网络等失常,一项指标十分合乎:

  留神时区问题,横坐标工夫点 + 8 小时。

  指标名称 ”Work Queue Latency”,提早?是这个问题吗?再看看 apiserver 的日志,发现居然也存在大量的超时日志:

{"log":"E0825 10:56:05.015507       1 controller.go:114] loading OpenAPI spec for \"v1alpha1.proxies.clusternet.io\"failed with: failed to retrieve openAPI spec, http error: ResponseCode: 503, Body: Error trying to reach service:'dial tcp 10.100.100.223:443: connect: connection timed out', Header: map[Content-Type: X-Content-Type-Options:[nosniff]]\n","stream":"stderr","time":"2022-08-25T02:56:05.015718744Z"}

  10.x.x.223 这个节点是什么呢?貌似是一个 serviceip,后端对应哪个服务呢?经查问发现是 clusternet-hub,是这个服务导致的吗?

  这里须要阐明下,测试环境容器集群总共有 3 个 master,10.x.x.21/10.x.x.22/10.x.x.23,而且监控显示的指标,以及谬误日志,只存在 22、23 两个节点。为什么这两个节点有异样,21 节点的 apiserver 却没有任何异样呢?

  另外发现,clusternet-hub 只有一个 pod,就在 10.x.x.21 节点。服务依赖如下所示:

  感觉特地像是 10.x.x.21 节点网络故障? 这里网络搭档不背锅,不要查不进去就说是网络起因。

  再回顾下 ingress 的谬误日志,统计所有服务的超时 upstream_addr,发现这些 pod 都集中在两个节点。而且容器平台的服务也刚好在 10.x.x.21 节点,其余服务的超时都集中在 10.x.x.55 节点。此时整个链路是这样的:

  红色线条的拜访,都呈现了连贯超时景象,难道真是这两个节点的网络呈现故障了吗?

确定起因

  这里须要阐明下测试环境的网络架构,基于 kube-router(ipvs + bgp 路由)实现的,kube-router 部署在每一个容器集群节点,ipvs 实现 service 负载平衡,bgp 路由实现 pod 跨节点通信。

  如上图所示,pod1 拜访 pod3 时,依赖 kube-router 在本节点生成的路由表。而如果 kube-router 异样之后,路由的缺失,将导致 pod 跨节点间的通信异样。

  查看 10.x.x.21 节点部署的 kube-router,发现 pod 在上午 11 点 17 分重新启动了(10.x.x.55 同样):

State:        Running
Started:      Thu, 25 Aug 2022 11:16:51 +0800
Last State:   Terminated
Reason:       Completed
Exit Code:    0
Started:      Thu, 25 Aug 2022 11:11:25 +0800
Finished:     Thu, 25 Aug 2022 11:16:50 +0800

  再查看 ingress 节点上部署的 kube-router 日志,显示 10 点 54 分 10.x.x.21 节点 Peer Down,11 点 17 分 10.x.x.21 节点 Peer Up(10.x.x.55 节点相似)

time="2022-08-25T10:54:07+08:00" level=info msg="Peer Down" Key=10.90.31.21 Reason=graceful-restart State=BGP_FSM_ESTABLISHED Topic=Peer
time="2022-08-25T10:58:48+08:00" level=info msg="Peer Down" Key=10.90.31.55 Reason=graceful-restart State=BGP_FSM_ESTABLISHED Topic=Peer

time="2022-08-25T11:17:02+08:00" level=info msg="Peer Up" Key=10.90.31.55 State=BGP_FSM_OPENCONFIRM Topic=Peer
time="2022-08-25T11:17:13+08:00" level=info msg="Peer Up" Key=10.90.31.21 State=BGP_FSM_OPENCONFIRM Topic=Peer

  依据这些日志,根本能够确定,kube-router 异样退出,导致 10.x.x.21/10.x.x.55 节点短时间内的不可达。这两个节点上的 kube-router 为什么异样重启呢?因为测试环境没有采集日志,之前的日志也已失落,目前具体起因也不得而知。

其余超时

  在剖析这起 case 时,发现还有局部服务继续存在 connect 超时状况,并且比例较小,也就是持续性的偶现超时。又是网络问题吗?

  在 ingress 节点与服务所在节点,同时开启 tcpdump 抓包,发现 ingress 节点失常发动 SYN 包,而且服务所在节点也失常收到了 SYN 包,然而却没有响应:

// 目标节点抓包
21:30:59.071873 IP 10.100.100.26.31506 > 10.0.0.183.10086: Flags [S], seq 2272650563, win 29200, options [mss 1460,sackOK,TS val 3041591460 ecr 0,nop,wscale 9], length 0
21:31:00.073425 IP 10.100.100.26.31506 > 10.0.0.183.10086: Flags [S], seq 2272650563, win 29200, options [mss 1460,sackOK,TS val 3041592462 ecr 0,nop,wscale 9], length 0
21:31:02.075437 IP 10.100.100.26.31506 > 10.0.0.183.10086: Flags [S], seq 2272650563, win 29200, options [mss 1460,sackOK,TS val 3041594464 ecr 0,nop,wscale 9], length 0

  为什么没有响应该 SYN 包呢,这里预计大概率是 tcp 队列溢出了(半连贯队列)。netstat 查看 socket 的统计信息:

netstat -antp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp      101      0 0.0.0.0:10086           0.0.0.0:*               LISTEN      1/java
tcp        0      0 10.0.0.183:10086       10.100.100.26:13138       SYN_RECV    -
tcp        0      0 10.0.0.183:10086       10.100.100.26:14460       SYN_RECV    -
tcp        0      0 10.0.0.183:10086       10.100.100.26:14354       SYN_RECV    -
tcp        0      0 10.0.0.183:10086       10.100.100.26:13250       SYN_RECV    -
tcp        0      0 10.0.0.183:10086       10.100.100.26:13476       SYN_RECV    -

  能够看到监听的 socket,Recv- Q 持续性大于 0,而且存在大量 SYN_RECV 状态的 tcp 连贯。

  LISTEN 状态下的 socket,Recv- Q 示意以后队列中期待利用程序处理的连贯申请数,大于 0 阐明有 tcp 连贯曾经建设胜利,然而应用程序却没有执行 accept 解决。

  为什么存在大量 SYN_RECV 状态的 tcp 连贯呢?阐明服务端收到 SYN 包之后,曾经向客户端返回了 SYN+ACK 包,在期待客户端 ACK 包。须要留神的是,当服务端 tcp 全连贯队列溢出时,收到的客户端 ACK 也会间接抛弃,而该连贯持续放弃在 SYN_RECV 状态(没法进入 ESTABLISHED 状态)。

  所以根本能够判定,服务端 tcp 半连贯以及全连贯队列溢出导致的连贯超时状况。这种状况就须要服务端程序调整 backlog 大小了(listen 函数的参数 backlog,当然 tcp 队列大小不仅由 backlog 参数决定,还依赖内核参数)。

  其实在某些状况下,tcp 队列溢出后,服务端并不是抛弃这个包,还有可能返回 RST,这时候客户端看到的谬误就是 ”connection reset by peer”。这些行为也有内核参数决定。

总结反思

  测试环境 k8s 集群网络架构基于 kube-router 实现,线上环境目前基于 cilium + bgp 实现,这些组件的底层原理还是须要钻研,不然遇到网络故障怎么排查?

  备注:k8s 网络架构不是一篇文章能介绍分明的,包含 tcp 协定全连贯队列 & 半连贯队列,这类常识往上文章很多,有趣味的读者能够本人钻研钻研。

参考文献

  • k8s 网络根底:https://www.cnblogs.com/bakar…
  • k8s 网络架构:https://my.oschina.net/u/4471…
  • kube-router:https://www.kube-router.io/docs/
  • cilium:https://docs.cilium.io/en/sta…
  • tcp 队列:https://segmentfault.com/a/11…

正文完
 0