问题现象
我发现这么一个问题,我的容器在同一个overlay网络中,但是发现跨节点访问有问题,具体表现为:
排查过程
没有思路,只好抓包来看,我监听了vxlan的4789端口(overlay是基于vxlan技术实现的),这是我请求的时候完整的通信过程:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
1 0.000000 10.0.1.3 10.0.1.6 TCP 124 37148 → 8080 [SYN] Seq=0 Win=64860 Len=0 MSS=1410 SACK_PERM TSval=1705177287 TSecr=0 WS=128
2 0.000739 10.0.1.6 10.0.1.3 TCP 124 8080 → 37148 [SYN, ACK] Seq=0 Ack=1 Win=64308 Len=0 MSS=1410 SACK_PERM TSval=4021339686 TSecr=1705177287 WS=128
3 0.000804 10.0.1.3 10.0.1.6 TCP 116 37148 → 8080 [ACK] Seq=1 Ack=1 Win=64896 Len=0 TSval=1705177288 TSecr=4021339686
4 0.000869 10.0.1.3 10.0.1.6 HTTP 197 GET / HTTP/1.1
5 0.001165 10.0.1.6 10.0.1.3 TCP 116 8080 → 37148 [ACK] Seq=1 Ack=82 Win=64256 Len=0 TSval=4021339687 TSecr=1705177288
6 0.008789 10.0.1.6 10.0.1.3 HTTP 1318 [TCP Previous segment not captured] Continuation
7 0.008853 10.0.1.3 10.0.1.6 TCP 128 [TCP Dup ACK 3#1] 37148 → 8080 [ACK] Seq=82 Ack=1 Win=64896 Len=0 TSval=1705177296 TSecr=4021339687 SLE=6991 SRE=8193
8 20.031896 10.0.1.6 10.0.1.3 TCP 116 [TCP Previous segment not captured] 8080 → 37148 [FIN, ACK] Seq=11278 Ack=82 Win=64256 Len=0 TSval=4021359718 TSecr=1705177296
9 20.031944 10.0.1.3 10.0.1.6 TCP 136 [TCP Dup ACK 3#2] 37148 → 8080 [ACK] Seq=82 Ack=1 Win=64896 Len=0 TSval=1705197319 TSecr=4021339687 SLE=11278 SRE=11279 SLE=6991 SRE=8193
10 80.504036 10.0.1.3 10.0.1.6 TCP 136 [TCP Keep-Alive] 37148 → 8080 [ACK] Seq=81 Ack=1 Win=64896 Len=0 TSval=1705257791 TSecr=4021339687 SLE=11278 SRE=11279 SLE=6991 SRE=8193
11 80.504836 10.0.1.6 10.0.1.3 TCP 116 [TCP Keep-Alive ACK] 8080 → 37148 [ACK] Seq=11279 Ack=82 Win=64256 Len=0 TSval=4021420191 TSecr=1705197319
12 142.968063 10.0.1.3 10.0.1.6 TCP 136 [TCP Keep-Alive] 37148 → 8080 [ACK] Seq=81 Ack=1 Win=64896 Len=0 TSval=1705320255 TSecr=4021339687 SLE=11278 SRE=11279 SLE=6991 SRE=8193
13 142.968782 10.0.1.6 10.0.1.3 TCP 104 8080 → 37148 [RST] Seq=1 Win=0 Len=0
|
由上面可以看出:
- TCP三次握手连接建立正常
- 客户端发送HTTP请求,服务端ACK确认
- 然后服务端发送了第一个HTTP响应段,但是客户端没有收到
- 客户端重传ACK,触发快速重传机制
- 但是服务端并没有收到客户端的重传ACK,导致其自己超时,发送RST结束连接
当然我也测了纯四层的nc探测,一切正常:
1
2
3
4
5
6
7
|
1 0.000000 10.0.1.3 10.0.1.6 TCP 124 52898 → 8080 [SYN] Seq=0 Win=64860 Len=0 MSS=1410 SACK_PERM TSval=1707997198 TSecr=0 WS=128
2 0.000235 10.0.1.6 10.0.1.3 TCP 124 8080 → 52898 [SYN, ACK] Seq=0 Ack=1 Win=64308 Len=0 MSS=1410 SACK_PERM TSval=4024159597 TSecr=1707997198 WS=128
3 0.000564 10.0.1.3 10.0.1.6 TCP 116 52898 → 8080 [ACK] Seq=1 Ack=1 Win=64896 Len=0 TSval=1707997198 TSecr=4024159597
4 0.000655 10.0.1.3 10.0.1.6 TCP 116 52898 → 8080 [FIN, ACK] Seq=1 Ack=1 Win=64896 Len=0 TSval=1707997198 TSecr=4024159597
5 0.001178 10.0.1.6 10.0.1.3 TCP 116 8080 → 52898 [ACK] Seq=1 Ack=2 Win=64384 Len=0 TSval=4024159598 TSecr=1707997198
6 0.004187 10.0.1.6 10.0.1.3 TCP 116 8080 → 52898 [FIN, ACK] Seq=1 Ack=2 Win=64384 Len=0 TSval=4024159601 TSecr=1707997198
7 0.004496 10.0.1.3 10.0.1.6 TCP 116 52898 → 8080 [ACK] Seq=2 Ack=2 Win=64896 Len=0 TSval=1707997202 TSecr=4024159601
|
这个问题应该是出在内核了,我首先查了下本地的操作系统内核版本:
1
2
|
$ uname -r
5.10.0-136.17.0.93.oe2203sp1.x86_64
|
然后进容器看了容器的发行版版本(不要问为啥不看容器内核版本)
1
2
|
$ cat /etc/redhat-release
CentOS Linux release 8.3.2011
|
CentOS 8是基于linux kernel 4的,这里可以猜想是不是内核版本不同,导致两者在网络协议实现上有一定的差异,尤其是在TCP连接状态跟踪和重传机制上会有差异,这会导致连接建立后,数据传输过程中出现异常,触发了这个问题。
然后我直接搞了很多个版本的base镜像,发现linux kernel在5以上(含5)都是正常的。
那问题已经很明确了,这个就是内核版本不同的兼容性问题。
解决方案
升级容器的base,使得发行版使用内核在5,最好是宿主机跟容器使用一样的操作系统。