openstack云主机内docker通信异常问题记录

最近项目组内部搭建了一套自动化构建环境用于进行版本的日常构建,但是搭建至今一直构建失败。那构建失败又是怎么导致的呢?现在就根据问题的现象去层层分析找到问题的根因。

  1. 问题的表现
    云平台创建了一个独立的虚拟机用于自动化编译构建。构建时编译脚本会自动创建docker,通过在docker内启动编译脚本进行项目镜像构建。每次编译启动不久就失败了,经过排查编译日志发现是在编译过程中通过curl下载docker的gpg就失败了。类似与下面的这个命令:$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - OK   。在启动编译后登录到容器中单独执行curl命令下载gpg也是失败。退出容器在该容器所在的宿主机中执行该命令,下载成功了。
  2. 定位过程
    根据问题现象推测是不是curl的报文没回来,决定通过抓包进行分析。容器使用的是bridge类型的网络模式,直接在容器所在的云主机进行抓包。使用wireshark来解析报文,过滤目的地址


    可以看到tcp三步握手的过程,curl使用了ssl与服务器端进行交互协商,但是在client之后就没有,server的hello应答。应答报文丢了。
     正常的ssl协商过程应该是这样的:下面这个报文是在云主机直接curl成功时候的在云主机网卡的抓包。

     从正常的流程和异常流程的对比可以确定的是在容器中curl出现了丢包的现象。那么为什么会丢包呢。初步怀疑是不是云主机所在的物理服务器丢了报文。找到该云主机所在的物理服务器进行抓包。
    容器内执行curl,抓包开始,结果在宿主机网卡上就没有抓到报文。看来网络报文的丢弃不是在云主机干的,是在宿主机就被丢了。那下一步又开始怀疑是不是宿主机压根就没收到这个报文呢。此处补下拓扑连接如下图:


    vm流量到外部是通过宿主机与border之间的 vxlan出去的,那宿主机没有收到报文,怀疑是不是border就没发出来呢。那下一步就到border与宿主机之间的链路出端口进行镜像抓包。结果是抓到了外部回复的报文,包含ssl协商的server-hello报文。这说明了什么,说明宿主机网卡把报文给丢了,没有进入内核协议栈。那报文为什么在网卡被丢了呢,再回过头去看下抓出来的tcp报文有什么差异呢?
    先看容器发出的tcp 握手报文,其中的mss大小为1460


    再看下正常的云主机内部执行curl的报文:其中MSS为1410.

     差异点出来了,容器里面执行curl协商的MSS大小是1460,而云主机执行curl tcp MSS大小为1410字节。我们知道tcp 协商MSS是根据接口的MTU计算得来的。那么说明云主机和容器接口的mtu是有差异的。

     MSS = MTU - (IP header size + TCP header size)  容器里面是1460,IP header和tcp header都是20字节,说明容器的接口MTU为1500。而云主机的接口MTU为1450。以太网接口标准定义接口MTU为1500。那云主机为什么事1450呢。此处先暂放已放,后面分析具体的原因。 现在明白了是以为MTU导致的丢包,那宿主机的MTU查询了下是1500,那为什么宿主机会丢包呢。

  3.  故障原因分析
    通过前面的现象和抓包我们找到了导致问题现象的原因,根本原因是因为接口MTU的不匹配导致的报文丢弃。但是这个时候又出现了疑问,宿主机的MTU是多少呢?我们登录宿主机查询了下,发现宿主机的MTU也是1500,既然是1500,server-hello为什么会被丢掉呢,server-hello最大是多大呢。分析下抓取的正常的报文:

     发现server-hello的大小是2874字节,为什么会这么大呢,网卡mtu不是才1500吗,MSS不是1410吗?是不是网卡开启了分片重组GRO LRO之类的。去查询了下网卡的配置:

     GRO开启,应该是分片重组上送了,所以会看到的一个超过1500的报文。那说明最大的报文已经达到了1500.1500正好是宿主机网卡的MTU,按道理不应该丢。但是别忘了,我们的宿主机内部的vm或者容器与border的通信使用的是vxlan封装。
    1500只是作为内部载荷,加上underlay报文udp及封装的vxlan报文头,报文超过就超过1500字节了,vxlan报文头占50个字节(14+20+8+8))这样在宿主机网卡上就会把报文丢弃了。

    为了验证该处猜测,将宿主机的MTU改大为1600,此时在宿主机网卡抓包,发现抓到了回来的vxlan报文。但是此时宿主机通了,但是云主机还是没有在其端口上抓到报文,我们前面查询了云主机协商的MTU仅为1410

  4. openstack虚拟机mtu的问题分析
    云主机是基于openstack创建的,那云主机的MTU大小为什么是1500呢,当前创建的云主机是双网卡的,一个用于管理登录,一个用于数据通信,我们发现双网卡的MTU并不相同,这就让人感觉有点迷糊了。云主机协商的MSS是1410,其中数据端口的MTU是1450,管理端口的MTU是1500.那我们的数据端口为什么是1450,而不是标准的1500呢。
    查询了下openstack里面关于创建的虚拟机的网络接口MTU的设置,云主机MTU的设置和其网络端口所在的网络类型有关。对于不通的类型创建的是不通的MTU大小的虚拟端口。

     因为当前云主机所在的云平台租户网络类型是vxlan,所以根据以上的规则,我们可以明白为什么创建的云主机数据网络接口MTU是1450了。那MSS自然就是MTU再减掉40字节,变成了1410了。

posted @ 2024-04-11 09:18  stephigher  阅读(70)  评论(0)    收藏  举报