tcpdump抓包docker容器之间网络内容
客户生产环境的客户端上传小文件是可以正常上传的,但在上传大文件到服务器时经常发生卡慢和超时问题,导致无法上传大文件。为了分析这个问题,我和同事捋了一下服务端架构,架构如下:Docker内部有容器A和容器B两个服务,容器B的端口12000映射到了宿主机上的端口12000,外部客户端可以正常访问。服务A的端口没有做映射,只允许Docker内部的容器互相访问。
tcpdump抓包docker容器之间网络内容
前言
客户生产环境的客户端上传小文件是可以正常上传的,但在上传大文件到服务器时经常发生卡慢和超时问题,导致无法上传大文件。
为了分析这个问题,我和同事捋了一下服务端架构,架构如下:
Docker内部有容器A和容器B两个服务,容器B的端口12000映射到了宿主机上的端口12000,外部客户端可以正常访问。服务A的端口没有做映射,只允许Docker内部的容器互相访问。
问题分析
客户端到服务器能正常上传小文件,说明网络是正常的。企业内部宽理论上也是够的,因此可以排除前面两个网络存在问题的可能性。剩下的可能性在于服务器内部容器B到容器A两个微服务之间的网络问题。
方案设计
现在要用tcpdump对容器A和容器B的网络进行抓包,该如何做到呐?
第一个方案
从宿主机监听容器A的端口2100,理论上行不通,因为端口没有映射。
第二个方案
在容器内部搭一个tcpdump容器,容器内部网络互通,端口2100可以被tcpdump容器访问,理论上可行,但实际验证下来没有抓到包。因为tcpdump容器本身可以理解为一个完整的操作系统,在里面开启监听,监听到的网卡只是tcpdump容器内部的虚拟网卡,而不是容器A和容器B通信的虚拟网卡。
第三个方案
参考了网上的文章,使用nsenter命令工具,借助这个工具,我们可以进入Linux系统的不同命名空间中并执行命令,docker中运行的容器本身就是一种被隔离的进程。
要实现抓包大致逻辑是:
- 在宿主机安装tcpdump工具;
- 使用docker命令找到Service A容器对应的宿主机的pid;
- 借助nsenter命令,使得tcpdump能够监听到流经Service A容器内部虚拟网卡的流量。
方案验证
安装tcpdump
网上下载tcpdump包,在宿主机安装tcpdump。
tcpdump依赖于 libpcap,因此需要先安装 libpcap。
解压libpcap-1.10.3.tar.gz包,并编译安装。
tar -zxvf libpcap-1.10.3.tar.gz
cd libpcap-1.10.3
./configure
make
make install
解压tcpdump并编译安装
tar -zxvf tcpdump-4.99.3.tar.gz
cd tcpdump-4.99.3
./configure
make
make install
映射关系查找
用下面命令查找要抓包的docker容器的容器ID,这里查找Service A的容器ID
docker ps | grep 容器名
得到Service A容器ID后,执行下面这条命令,找到容器在宿主机上对应的PID
docker inspect --format "{{.State.Pid}}" 容器ID
下图是容器ID(f0541503c0e1)对应的宿主机上的PID(31891)
网络内容抓包
下面命令,PID替换为上一步找到的PID,port 是Service A服务的端口,host 后面是nginx容器的IP,这个IP需要进入容器内部使用命令 ip addr 查看,默认是网卡eth0对应的IP。
nsenter -n -t PID tcpdump -i eth0 dst port 端口 and src host 容器内部IP
nsenter
:
是一个用于进入指定命名空间的工具。在 Linux 系统中,命名空间用于隔离资源,如进程、网络、挂载点等。-n
:表示进入网络命名空间。-t PID
:表示目标进程的 PID(进程ID)。这个 PID 通常是一个容器进程的 ID,所以该命令的意图是进入容器的网络命名空间。- -i eth0: 指定要捕获流量的网络接口为
eth0
- dst port:表示要监听的目标端口
- src host:表示要监听的源地址IP
如果要输出抓包内容到文件,可以在上面命令后面追加参数-w /xxx/network.pcap,表示把抓包内容输出到宿主机/xxx路径下的network.pcap文件中,文件名可以自定义。
nsenter -n -t PID tcpdump -i eth0 dst port 2048 and src host 容器内部ip -w /xxx/network.cap
- -w:这是一个
tcpdump
的选项,用于指定将捕获的数据包写入文件的路径
修改完上面这条命令为对应的服务参数后,在宿主机上执行,开始抓包从nginx服务到serviceA的网络。
上传一个273byte(字节)的文件,下面这个是抓到的包内容
16:05:21.396649 IP 10.0.2.22.40270 > xxx-server.dls-monitor: Flags [S], seq 2702839680, win 28200, options [mss 1410,sackOK,TS val 475563759 ecr 0,nop,wscale 7], length 0
16:05:21.396682 IP 10.0.2.22.40270 > xxx-server.dls-monitor: Flags [.], ack 3865746325, win 221, options [nop,nop,TS val 475563759 ecr 475563759], length 0
16:05:21.396792 IP 10.0.2.22.40270 > xxx-server.dls-monitor: Flags [P.], seq 0:563, ack 1, win 221, options [nop,nop,TS val 475563759 ecr 475563759], length 563
16:05:21.396829 IP 10.0.2.22.40270 > xxx-server.dls-monitor: Flags [P.], seq 563:2021, ack 1, win 221, options [nop,nop,TS val 475563759 ecr 475563759], length 1458
16:05:21.476387 IP 10.0.2.22.40270 > xxx-server.dls-monitor: Flags [.], ack 165, win 229, options [nop,nop,TS val 475563839 ecr 475563839], length 0
16:05:21.476548 IP 10.0.2.22.40270 > xxx-server.dls-monitor: Flags [F.], seq 2021, ack 165, win 229, options [nop,nop,TS val 475563839 ecr 475563839], length 0
16:05:21.476822 IP 10.0.2.22.40270 > xxx-server.dls-monitor: Flags [.], ack 166, win 229, options [nop,nop,TS val 475563839 ecr 475563839], length 0
分析抓包内容
将上面抓到的网络内容交由AI分析,AI对这段信息的分析如下:
- 第一行数据包:
-
- 时间戳:16:05:21.396649
- IP地址:10.0.2.22.40270 > xxx-server.dls-monitor
- Flags:[S],表示这是一个SYN(同步)报文
- seq:2702839680,表示序列号为2702839680
- win:28200,表示窗口大小为28200
- options:[mss 1410,sackOK,TS val 475563759 ecr 0,nop,wscale 7],表示使用了最大报文段长度(MSS)为1410,支持选择性确认(SACK),时间戳值为475563759,扩展最大报文段长度(WSCALE)为7
- length:0,表示该报文没有负载数据
- 第二行数据包:
-
- 时间戳:16:05:21.396682
- IP地址:10.0.2.22.40270 > xxx-server.dls-monitor
- Flags:[.],表示这是一个ACK(确认)报文
- ack:3865746325,表示确认号为3865746325
- win:221,表示窗口大小为221
- options:[nop,nop,TS val 475563759 ecr 475563759],表示时间戳值为475563759,扩展最大报文段长度(ECR)为475563759
- length:0,表示该报文没有负载数据
- 第三行数据包:
-
- 时间戳:16:05:21.396792
- IP地址:10.0.2.22.40270 > xxx-server.dls-monitor
- Flags:[P.],表示这是一个PSH(推送)和ACK(确认)报文
- seq:0:563,表示序列号范围为0到563
- ack:1,表示确认号为1
- win:221,表示窗口大小为221
- options:[nop,nop,TS val 475563759 ecr 475563759],表示时间戳值为475563759,扩展最大报文段长度(ECR)为475563759
- length:563,表示该报文的负载数据长度为563字节
- 第四行数据包:
-
- 时间戳:16:05:21.396829
- IP地址:10.0.2.22.40270 > xxx-server.dls-monitor
- Flags:[P.],表示这是一个PSH(推送)和ACK(确认)报文
- seq:563:2021,表示序列号范围为563到2021
- ack:1,表示确认号为1
- win:221,表示窗口大小为221
- options:[nop,nop,TS val 475563759 ecr 475563759],表示时间戳值为475563759,扩展最大报文段长度(ECR)为475563759
- length:1458,表示该报文的负载数据长度为1458字节
- 第五行数据包:
-
- 时间戳:16:05:21.476387
- IP地址:10.0.2.22.40270 > xxx-server.dls-monitor
- Flags:[.],表示这是一个ACK(确认)报文
- ack:165,表示确认号为165
- win:229,表示窗口大小为229
- options:[nop,nop,TS val 475563839 ecr 475563839],表示时间戳值为475563839,扩展最大报文段长度(ECR)为475563839
- length:0,表示该报文没有负载数据
- 第六行数据包:
-
- 时间戳:16:05:21.476548
- IP地址:10.0.2.22.40270 > xxx-server.dls-monitor
- Flags:[F.],表示这是一个FIN(结束)和ACK(确认)报文
- seq:2021,表示序列号为2021
- ack:165,表示确认号为165
- win:229,表示窗口大小为229
- options:[nop,nop,TS val 475563839 ecr 475563839],表示时间戳值为475563839,扩展最大报文段长度(ECR)为475563839
- length:0,表示该报文没有负载数据
- 第七行数据包:
-
- 时间戳:16:05:21.476822
- IP地址:10.0.2.22.40270 > xxx-server.dls-monitor
- Flags:[.],表示这是一个ACK(确认)报文
- ack:166,表示确认号为166
- win:229,表示窗口大小为229
- options:[nop,nop,TS val 475563839 ecr 475563839],表示时间戳值为475563839,扩展最大报文段长度(ECR)为475563839
- length:0,表示该报文没有负载数据
上面这段分析的内容是关于网络数据包的抓取和分析。根据tcpdump工具抓取的数据包信息,可以得出以下结论:
- 第一行数据包是一个SYN报文,表示建立连接的请求。
- 第二行数据包是一个ACK报文,表示确认连接的建立。
- 第三行和第四行数据包都是PSH和ACK报文,表示传输数据的请求和确认。
- 第五行数据包是一个ACK报文,表示确认数据的接收。
- 第六行数据包是一个FIN和ACK报文,表示结束连接的请求和确认。
- 第七行数据包是一个ACK报文,表示确认连接的关闭。
具体的网络数据包分析可使用wireshark。
备注说明:
- 报文分析和报文内容总结由AI讯飞星火生成。
- 上面的操作是在测试环境验证抓包的可行性,不是实际生产环境大文件上传慢时抓的包。
参考
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)