页面加载中,请稍候
来源:开源Linux发布时间:2023-05-16658浏览
询问 AI
来源:https://www.cnblogs.com/Cylon/p/16611503.html
本文将引入一个思路:“在 Kubernetes 集群发生网络异常时如何排查”。文章将引入 Kubernetes 集群中网络排查的思路,包含网络异常模型,常用工具,并且提出一些案例以供学习。那么整个 Pod 网络异常分类可以如下图所示:

总结一下,Pod 最常见的网络故障有,网络不可达(ping 不通);端口不可达(telnet 不通);DNS 解析异常(域名不通)与大数据包丢失(大包不通)。
在了解到常见的网络异常后,在排查时就需要使用到一些网络工具才可以很有效的定位到网络故障原因,下面会介绍一些网络排查工具。
tcpdumptcpdump 网络嗅探器,将强大和简单结合到一个单一的命令行界面中,能够将网络中的报文抓取,输出到屏幕或者记录到文件中。
各系统下的安装:
查看指定接口上的所有通讯。
语法:
捕获所有网络接口:
tcpdump-D
按 IP 查找流量:最常见的查询之一 host,可以看到来往于 1.1.1.1 的流量。
tcpdumphost1.1.1.1
按源 / 目的 地址过滤:如果只想查看来自 / 向某方向流量,可以使用 src 和 dst。
tcpdumpsrc|dst1.1.1.1
通过网络查找数据包:
使用 net 选项,来要查找出 / 入某个网络或子网的数据包。
tcpdumpnet1.2.3.0/24
使用十六进制输出数据包内容:
hex 可以以 16 进制输出包的内容
tcpdump-c1-Xicmp
查看特定端口的流量:
使用 port 选项来查找特定的端口流量。
tcpdumpport3389
tcpdumpsrcport1025
查找端口范围的流量:
tcpdumpportrange21-23
过滤包的大小:
如果需要查找特定大小的数据包,可以使用以下选项。你可以使用 less,greater。
tcpdumpless32
tcpdumpgreater64
tcpdump<=128
捕获流量输出为文件:
-w可以将数据包捕获保存到一个文件中以便将来进行分析。这些文件称为 PCAP(PEE-cap)文件,它们可以由不同的工具处理,包括 Wireshark 。
tcpdumpport80-wcapture_file
组合条件:
tcpdump 也可以结合逻辑运算符进行组合条件查询:
tcpdump-ieth0-nnhost220.181.57.216and10.0.0.1#主机之间的通讯
tcpdump-ieth0-nnhost220.181.57.216or10.0.0.1
#获取10.0.0.1与10.0.0.9或10.0.0.1与10.0.0.3之间的通讯
tcpdump-ieth0-nnhost10.0.0.1and\(10.0.0.9or10.0.0.3\)
原始输出:
并显示人类可读的内容进行输出包(不包含内容)。
tcpdump-ttnnvvS-ieth0
tcpdump-ttnnvvS-ieth0
IP 到端口:
让我们查找从某个 IP 到端口任何主机的某个端口所有流量。
tcpdump-nnvvSsrc10.5.2.3anddstport3389
去除特定流量:
可以将指定的流量排除,如这显示所有到 192.168.0.2 的 非 ICMP 的流量。
tcpdumpdst192.168.0.2andsrcnetandnoticmp
来自非指定端口的流量,如,显示来自不是 SSH 流量的主机的所有流量。
tcpdump-vvsrcmarsandnotdstport22
选项分组:
在构建复杂查询时,必须使用单引号 '。单引号用于忽略特殊符号 () ,以便于使用其他表达式(如 host, port, net 等)进行分组。
tcpdump'src10.0.2.4and(dstport3389or22)'
过滤 TCP 标记位。
TCP RST:
下面的过滤器可以找到这些不同的数据包,因为tcp[13]看的是TCP头中的偏移量13,数字代表字节内的位置,而!=0意味着相关的标志被设置为1,即它是打开的。
tcpdump'tcp[13]4!=0'
tcpdump'tcp[tcpflags]==tcp-rst'
TCP SYN:
tcpdump'tcp[13]2!=0'
tcpdump'tcp[tcpflags]==tcp-syn'
同时忽略 SYN 和 ACK 标志的数据包。
tcpdump'tcp[13]=18'
TCP URG:
tcpdump'tcp[13]32!=0'
tcpdump'tcp[tcpflags]==tcp-urg'
TCP ACK:
tcpdump'tcp[13]16!=0'
tcpdump'tcp[tcpflags]==tcp-ack'
TCP PSH:
tcpdump'tcp[13]8!=0'
tcpdump'tcp[tcpflags]==tcp-push'
TCP FIN:
tcpdump'tcp[13]1!=0'
tcpdump'tcp[tcpflags]==tcp-fin'
查找 http 包。
查找 user-agent 信息:
tcpdump-vvAls0|grep'User-Agent:'
查找只是 GET 请求的流量:
tcpdump-vvAls0|grep'GET'
查找 http 客户端 IP:
tcpdump-vvAls0|grep'Host:'
查询客户端 cookie:
tcpdump-vvAls0|grep'Set-Cookie|Host:|Cookie:'
查找 DNS 流量:
tcpdump-vvAs0port53
查找对应流量的明文密码:
tcpdumpporthttporportftporportsmtporportimaporportpop3orporttelnet-lA|egrep-i-B5'pass=|pwd=|log=|login=|user=|username=|pw=|passw=|passwd=|password=|pass:|user:|username:|password:|login:|pass|user'
wireshark 追踪流:wireshare 追踪流可以很好的了解出在一次交互过程中都发生了那些问题。
wireshare 选中包,右键选择 “追踪流“ 如果该包是允许的协议是可以打开该选项的。
关于抓包节点和抓包设备:
如何抓取有用的包,以及如何找到对应的接口,有以下建议:
nsenternsenter 是一款可以进入进程的名称空间中。例如,如果一个容器以非 root 用户身份运行,而使用 docker exec 进入其中后,但该容器没有安装 sudo 或未 netstat ,并且您想查看其当前的网络属性,如开放端口,这种场景下将如何做到这一点?nsenter 就是用来解决这个问题的。nsenter(namespace enter)可以在容器的宿主机上使用 nsenter 命令进入容器的命名空间,以容器视角使用宿主机上的相应网络命令进行操作。当然需要拥有 root 权限。nsenter 的 c 使用语法为,nsenter -t pid -n <commond>,-t接 进程 ID 号,-n表示进入名称空间内,为执行的命令。实例:如我们有一个 Pod 进程 ID 为 30858,进入该 Pod 名称空间内执行 ifconfig ,如下列所示:$ps-ef|greptail
root1763662887020:19pts/200:00:00grep--color=autotail
root3085830838015:55?00:00:01tail-f
$nsenter-t30858-nifconfig
eth0:flags=4163<UP,BROADCAST,RUNNING,MULTICAST>mtu1480
inet192.168.1.213netmask255.255.255.0broadcast192.168.1.255
ether5e:d5:98:af:dc:6btxqueuelen0(Ethernet)
RXpackets92bytes9100(8.8KiB)
RXerrors0dropped0overruns0frame0
TXpackets92bytes8422(8.2KiB)
TXerrors0dropped0overruns0carrier0collisions0
lo:flags=73<UP,LOOPBACK,RUNNING>mtu65536
inet127.0.0.1netmask255.0.0.0
looptxqueuelen1000(LocalLoopback)
RXpackets5bytes448(448.0B)
RXerrors0dropped0overruns0frame0
TXpackets5bytes448(448.0B)
TXerrors0dropped0overruns0carrier0collisions0
net1:flags=4163<UP,BROADCAST,RUNNING,MULTICAST>mtu1500
inet10.1.0.201netmask255.255.255.0broadcast10.1.0.255
etherb2:79:f9:dd:2a:10txqueuelen0(Ethernet)
RXpackets228bytes21272(20.7KiB)
RXerrors0dropped0overruns0frame0
TXpackets216bytes20272(19.7KiB)
TXerrors0dropped0overruns0carrier0collisions0
如何定位 Pod 名称空间:
首先需要确定 Pod 所在的节点名称。
$kubectlgetpods-owide|awk'{print$1,$7}'
NAMENODE
netbox-85865d5556-hfg6vmaster-machine
netbox-85865d5556-vlgr4node01
如果 Pod 不在当前节点还需要用 IP 登录则还需要查看 IP(可选)。
$kubectlgetpods-owide|awk'{print$1,$6,$7}'
NAMEIPNODE
netbox-85865d5556-hfg6v192.168.1.213master-machine
netbox-85865d5556-vlgr4192.168.0.4node01
接下来,登录节点,获取容器 lD,如下列所示,每个 pod 默认有一个 pause 容器,其他为用户 yaml 文件中定义的容器,理论上所有容器共享相同的网络命名空间,排查时可任选一个容器。
$dockerps|grepnetbox-85865d5556-hfg6v
6f8c58377aaef78dd05f11ff"tail-f"45hoursagoUp45hoursk8s_netbox_netbox-85865d5556-hfg6v_default_4a8e2da8-05d1-4c81-97a7-3d76343a323a_0
b9c732ee457eregistry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.1"/pause"45hoursagoUp45hoursk8s_POD_netbox-85865d5556-hfg6v_default_4a8e2da8-05d1-4c81-97a7-3d76343a323a_0
接下来获得获取容器在节点系统中对应的进程号,如下所示:
$dockerinspect--format"{{.State.Pid}}"6f8c58377aae
30858
最后就可以通过 nsenter 进入容器网络空间执行命令了。
papingpaping 命令可对目标地址指定端口以 TCP 协议进行连续 ping,通过这种特性可以弥补 ping ICMP 协议,以及 nmap、telnet 只能进行一次操作的的不足;通常情况下会用于测试端口连通性和丢包率。
paping download[2]:
paping 还需要安装以下依赖,这取决于你安装的 paping 版本
$paping-h
papingv1.5.5-Copyright(c)2011MikeLovell
Syntax:paping[options]destination
Options:
-?,--helpdisplayusage
-p,--portNsetTCPportN(required)
--nocolorDisablecoloroutput
-t,--timeouttimeoutinmilliseconds(default1000)
-c,--countNsetnumberofcheckstoN
mtrmtr 是一个跨平台的网络诊断工具,将 traceroute 和 ping 的功能结合到一个工具。与 traceroute 不同的是 mtr 显示的信息比起 traceroute 更加丰富:通过 mtr 可以确定网络的条数,并且可以同时打印响应百分比以及网络中各跳跃点的响应时间。
简单的使用示例:
最简单的示例,就是后接域名或 IP,这将跟踪整个路由。
$mtrgoogle.com
Start:ThuJun2812:10:132018
HOST:TecMintLoss%SntLastAvgBestWrstStDev
1.|--192.168.0.10.0%50.30.30.30.40.0
2.|--5.5.5.2110.0%50.70.90.71.30.0
3.|--209.snat-111-91-120.hns.n80.0%57.17.17.17.10.0
4.|--72.14.194.2260.0%51.92.91.94.41.1
5.|--108.170.248.1610.0%52.93.52.04.30.7
6.|--216.239.62.2370.0%53.06.22.918.36.7
7.|--bom05s12-in-f14.1e100.net0.0%52.12.42.03.80.5
-n强制 mtr 打印 IP 地址而不是主机名。
$mtr-ngoogle.com
Start:ThuJun2812:12:582018
HOST:TecMintLoss%SntLastAvgBestWrstStDev
1.|--192.168.0.10.0%50.30.30.30.40.0
2.|--5.5.5.2110.0%50.90.90.81.10.0
3.|--???100.050.00.00.00.00.0
4.|--72.14.194.2260.0%52.02.01.92.00.0
5.|--108.170.248.1610.0%52.32.32.22.40.0
6.|--216.239.62.2370.0%53.03.23.03.30.0
7.|--172.217.160.1740.0%53.73.62.05.31.4
-b同时显示 IP 地址与主机名。
$mtr-bgoogle.com
Start:ThuJun2812:14:362018
HOST:TecMintLoss%SntLastAvgBestWrstStDev
1.|--192.168.0.10.0%50.30.30.30.40.0
2.|--5.5.5.2110.0%50.70.80.61.00.0
3.|--209.snat-111-91-120.hns.n0.0%51.41.61.32.10.0
4.|--72.14.194.2260.0%51.82.11.82.60.0
5.|--108.170.248.2090.0%52.01.91.82.00.0
6.|--216.239.56.1150.0%52.42.72.42.90.0
7.|--bom07s15-in-f14.1e100.net0.0%53.72.21.73.70.9
-c跟一个具体的值,这将限制 mtr ping 的次数,到达次数后会退出。
$mtr-c5google.com
如果需要指定次数,并且在退出后保存这些数据,使用-r flag。
$mtr-r-c5google.com>1
$cat1
Start:SunAug2122:06:492022
HOST:xxxxx.xxxxx.xxxx.xxxxLoss%SntLastAvgBestWrstStDev
1.|--gateway0.0%50.6146.80.6420.2191.4
2.|--212.xx.21.2410.0%50.41.00.42.30.5
3.|--188.xxx.106.1240.0%50.71.10.72.10.5
4.|--???100.050.00.00.00.00.0
5.|--72.14.209.890.0%543.243.343.143.30.0
6.|--108.xxx.250.330.0%543.243.143.143.20.0
7.|--108.xxx.250.340.0%543.743.643.543.70.0
8.|--142.xxx.238.820.0%560.660.960.661.20.0
9.|--142.xxx.238.640.0%559.767.559.389.813.2
10.|--142.xxx.37.810.0%562.762.962.663.50.0
11.|--142.xxx.229.850.0%561.060.960.761.30.0
12.|--xx-in-f14.1e100.net0.0%559.058.958.959.00.0
默认使用的是 ICMP 协议-i,可以指定 -u、-t 使用其他协议。
mtr--tcpgoogle.com
-m 指定最大的跳数。
mtr -m 35 216.58.223.78
-s 指定包的大小。
mtr 输出的数据:
columdescribelast最近一次的探测延迟值avg探测延迟的平均值best探测延迟的最小值wrst探测延迟的最大值stdev标准偏差。越大说明相应节点越不稳定丢包判断:
任一节点的 Loss%(丢包率)如果不为零,则说明这一跳网络可能存在问题。导致相应节点丢包的原因通常有两种。
Notes:
如果随后节点均没有丢包,则通常说明异常节点丢包是由于运营商策略限制所致。可以忽略相关丢包。
如果随后节点也出现丢包,则通常说明节点确实存在网络异常,导致丢包。对于这种情况,如果异常节点及其后续节点连续出现丢包,而且各节点的丢包率不同,则通常以最后几跳的丢包率为准。如链路测试在第 5、6、7 跳均出现了丢包。最终丢包情况以第 7 跳作为参考。
延迟判断:
由于链路抖动或其它因素的影响,节点的 Best 和 Worst 值可能相差很大。而 Avg(平均值)统计了自链路测试以来所有探测的平均值,所以能更好的反应出相应节点的网络质量。
而 StDev(标准偏差值)越高,则说明数据包在相应节点的延时值越不相同(越离散)。所以标准偏差值可用于协助判断 Avg 是否真实反应了相应节点的网络质量。
例如,如果标准偏差很大,说明数据包的延迟是不确定的。可能某些数据包延迟很小(例如:25ms),而另一些延迟却很大(例如:350ms),但最终得到的平均延迟反而可能是正常的。所以此时 Avg 并不能很好的反应出实际的网络质量情况。
这就需要结合如下情况进行判断:
Tips:对于更多的网络工具的使用可以参考这篇文章[3]。
Pod网络异常时排查思路,可以按照下图所示:

Pod network troubleshooting idea
测试环境 Kubernetes 节点扩容后无法访问集群 clusterlP 类型的 registry 服务。
环境信息:
IPHostnamerole10.153.204.15yq01-aip-aikefu12worknode 节点(本次扩容的问题节点)10.153.203.14yq01-aip-aikefu31master 节点10.61.187.42yq01-aip-aikefu2746f8e9master 节点10.61.187.48yq01-aip-aikefu30b61e25master 节点(本次 registry 服务 Pod 所在 节点)现象:
分析思路:
怀疑方向:
排查过程:
排查问题节点的 kube-proxy
执行kubectl get pod -owide -nkube-system l grep kube-proxy查看kube-proxy Pod的状态,问题节点上的 kube-proxy Pod 为 running 状态
执行kubecti logs <nodename> <kube-proxy pod name> -nkube-system查看问题节点 kube-proxy 的 Pod 日志,没有异常报错
在问题节点操作系统上执行iptables -S -t nat查看 iptables 规则
排查过程:
确认存在到 Registry 服务的 Cluster lP 10.233.0.100 的 KUBE-SERVICES 链,跳转至 KUBE-SVC-* 链做负载均衡,再跳转至 KUBE-SEP-* 链通过 DNAT 替换为服务后端 Pod 的 IP 10.233.65.46。因此判断 iptables 规则无异常执行 route-n 查看问题节点存在访问 10.233.65.46 所在网段的路由,如图所示:
10.233.65.46 路由
查看对端的回程路由:

回程路由
以上排查证明问题原因不是 CNI 插件或者 kube-proxy 异常导致,因此需要在访问链路上抓包,判断问题原因、问题节点执行curl 10.233.0.100:5000,在问题节点和后端 pod 所在节点的 flannel.1 上同时抓包发包节点一直在重传,Cluster lP 已 DNAT 转换为后端 Pod IP,如图所示:

抓包过程,发送端
后端 Pod( Registry 服务)所在节点的 flannel.1 上未抓到任何数据包,如图所示:
抓包过程,服务端
请求 service 的 ClusterlP 时,在两端物理机网卡抓包,发包端如图所示,封装的源端节点 IP 是 10.153.204.15,但一直在重传:
图片包传送过程,发送端
收包端收到了包,但未回包,如图所示:

图片包传送过程,服务端
由此可以知道,NAT 的动作已经完成,而只是后端 Pod(Registry 服务)没有回包,接下来在问题节点执行 curl10.233.65.46:5000,在问题节点和后端( registry 服务)Pod 所在节点的 flannel.1 上同时抓包,两节点收发正常,发包如图所示:

正常包发送端

正常包接收端
接下来在两端物理机网卡接口抓包,因为数据包通过物理机网卡会进行 vxlan 封装,需要抓 vxlan 设备的 8472 端口,发包端如图所示:

问题节点物理机网卡接口抓包
发现网络链路连通,但封装的 IP 不对,封装的源端节点 IP 是 10.153.204.228,但是存在问题节点的 IP 是 10.153.204.15。后端 Pod 所在节点的物理网卡上抓包,注意需要过滤其他正常节点的请求包,如图所示;发现收到的数据包,源地址是 10.153.204.228,但是问题节点的 IP 是 10.153.204.15。
对端节点物理机网卡接口抓包
此时问题以及清楚了,是一个 Pod 存在两个 IP,导致发包和回包时无法通过隧道设备找到对端的接口,所以发可以收到,但不能回。问题节点执行 ip addr,发现网卡 enp26s0f0 上配置了两个 IP,如图所示:
问题节点 IP
进一步查看网卡配置文件,发现网卡既配置了静态 IP,又配置了 dhcp 动态获取 IP。如图所示:
问题节点网卡配置
最终定位原因为问题节点既配置了 dhcp 获取 IP,又配置了静态 IP,导致 IP 冲突,引发网络异常。解决方法:修改网卡配置文件 /etc/sysconfig/network-scripts/ifcfg-enp26s0f0 里 BOOTPROTO="dhcp"为 BOOTPROTO="none";重启 docker 和 kubelet 问题解决。集群外云主机调用集群内应用超时问题现象:Kubernetes 集群外云主机以 http post 方式访问 Kubernetes 集群应用接口超时。
环境信息:Kubernetes 集群:calicoIP-IP 模式,应用接口以 nodeport 方式对外提供服务。
客户端:Kubernetes 集群之外的云主机。
通过抓包结果分析结果为 TCP 链接建立没有问题,但是在传输大数据的时候会一直重传 1514 大小的第一个数据包直至超时。怀疑是链路两端 MTU 大小不一致导致(现象:某一个固定大小的包一直超时的情况)。如图所示,1514 大小的包一直在重传。报文 1-3 TCP 三次握手正常。报文 1 info 中 MSS 字段可以看到 MSS 协商为 1460,MTU=1460+20bytes(IP 包头)+20bytes(TCP 包头)=1500。报文 7 Kubernetes 主机确认了包 4 的数据包,但是后续再没有对数据的 ACK。报文 21-29 可以看到云主机一直在发送后面的数据,但是没有收到 Kubernetes 节点的 ACK,结合 Pod 未收到任何报文,表明是 Kubernetes 节点和 Pod 通信出现了问题。
wireshark 分析
在云主机上使用 ping -s 指定数据包大小,发现超过 1400 大小的数据包无法正常发送。结合以上情况,定位是云主机网卡配置的 MTU 是 1500,tunl0 配置的 MTU 是 1440,导致大数据包无法发送至 tunl0 ,因此 Pod 没有收到报文,接口调用失败。解决方法:修改云主机网卡 MTU 值为 1440,或者修改 Calico 的 MTU 值为 1500,保持链路两端 MTU 值一致。集群 Pod 访问对象存储超时环境信息:公有云环境,Kubernetes 集群节点和对象存储在同一私有网络下,网络链路无防火墙限制 Kubernetes 集群开启了节点自动弹缩(CA)和 Pod 自动弹缩(HPA),通过域名访问对象存储,Pod 使用集群 DNS 服务,集群 DNS 服务配置了用户自建上游 DNS 服务器。排查过程:
10T 技术资源大放送!包括但不限于:Linux、虚拟化、容器、云计算、网络、Python、Go 等。在开源Linux公众号内回复10T,即可免费获取!
新闻来源:开源Linux,文中所述为作者独立观点,不代表icspec立场。更多精彩资讯请下载icspec App。如对本稿件有异议,请联系微信客服specltkj。
暂无评论哦,快来评论一下吧!
2026-07-21
2026-06-09