问题描述
近期在我的Miku Cluster集群上出现了很多网络问题,包括但不限于:
- 部署在k8s集群内的网站响应异常缓慢(Kuboard点一下得响应5秒多,有的时候直接404)
- 部署在k8s集群内的网站行为异常(Alist无法加载js,存储驱动异常等)
- 部署在k8s集群内的网站失联(404, 502, etc.)
- 部署在k8s集群内的本地镜像库上传大的Layer有很大概率会超时
- 使用scp命令在内网传输文件时,网速忽高忽低,经常stall
部分问题截图展示:
其实只是个小问题,然而却磕磕绊绊耗费了我两周的时间。下面记录我排查这一问题的过程。
环境概述
为了帮助读者理解,简要介绍一下目前的网络环境。
我有5台设备(节点),地理位置和带宽情况如下:
- A: 湖北,上下带宽10/40Mbps
- B: 香港,上下带宽5/5Mbps
- C: 重庆,家用电信大带宽
- D: 宁夏,家用广电小水管,大概有个30Mbps左右
- E: 宁夏,家用广电小水管,大概有个30Mbps左右
为了使这些异地设备加入同一内网,使用了Softether VPN进行了组网(CIDR为10.10.10.0/24)。Softether Server使用二层网桥,没有使用Secure NAT,其他配置基本都是默认配置。
内网组建完毕后,在这5台设备上使用Sealos部署了Kubernetes集群,版本是1.27.7,即Miku Cluster(老二次元了)。网络插件使用Cilium。Ingress Controller使用Traefik,其Service NodePort监听0.0.0.0
的某个http端口。
A节点作为国内域名解析的目标节点,即整个集群的Entrypoint。在A节点的操作系统上(k8s外)安装nginx,监听80和443端口,卸载tls后将对应流量转发到集群Traefik监听的http端口。
排查步骤
镜像push异常,排查Nginx
某天我发现GitLab CI/CD推送镜像失败了,原因是推送超时。
推送目标是Harbor搭建的本地镜像仓库,部署于k8s上,后端存储位于阿里云OSS。
后来经过反复测试,发现在手动push镜像时,较小的Layer大概率成功,较大的Layer小概率成功,比较尴尬。而且Layer push完毕后进度条会卡在100%很久才会变成Pushed,对于大的Layer,基本等不到Pushed状态就会超时重试。
对于这个情况,第一反应是Nginx可能限制了proxy_body_max_size
(说实话已经4202年了这个默认值是时候改大一点了)。然而尝试了很多值,甚至改成了无限制,push依然失败。
后来后知后觉去看了下nginx的错误日志,发现是上游超时了。
看来是冤枉nginx了。
Nginx上游超时,检查Traefik
既然nginx报错上游超时,那么就来检查下上游的Traefik。
Traefik是Miku Cluster中的默认Ingress Class的Controller,可以理解为k8s的入口反代。首先看了下Traefik的日志,没有什么相关的报错,只有一些不规范配置的警告。
经过查询,我发现可以把Traefik的日志的级别从默认的INFO调整为DEBUG。也许有什么错误被隐藏在DEBUG日志中了?感到胜利就在前方,我修改了Traefik的Helm Chart部署配置:
logs:
general:
level: "DEBUG" # Default: INFO
然后又进行一次失败的push后,来到日志,我看到了满页的调试信息,而且每秒都会刷新很多新的信息。在粗略阅读一遍后,我认为这些调试日志与这个问题并没有很大的关系,或者说要从这些海量的调试日志中找出一丝与超时相关的信息,难度还是太大了点。或许我可以先尝试其他方法,实在不行再来阅读这堆调试日志。
由于日志太多且很难发现其中的关键信息,这里就不贴出日志了。
我开始排查Traefik是否也有类似nginx的对请求体的限制。经过搜索,我看到了几个相关的GitHub Traefik项目内的Issue,其中一个是Can't upload docker images larger than 400MB or 2GB via traefik 3.0 3.0.1 3.0.2 proxy #10805。了解到Traefik部署于k8s中会限制连接的时间,默认为60秒,超过后就断开,这主要是为了防止恶意请求建立过多空连接而不释放,以此来消耗服务器资源。为了测试去除这一限制能否使镜像推送正常,我在chart values中设置了超时为600秒:
ports:
web:
transport:
respondingTimeouts:
readTimeout: 600 # @schema type:[string, integer, null]
writeTimeout: 600 # @schema type:[string, integer, null]
idleTimeout: 600 # @schema type:[string, integer, null]
lifeCycle:
requestAcceptGraceTimeout: # @schema type:[string, integer, null]
graceTimeOut: # @schema type:[string, integer, null]
keepAliveMaxRequests: # @schema type:[integer, null]; minimum:0
keepAliveMaxTime: # @schema type:[string, integer, null]
websecure:
transport:
respondingTimeouts:
readTimeout: 600 # @schema type:[string, integer, null]
writeTimeout: 600 # @schema type:[string, integer, null]
idleTimeout: 600 # @schema type:[string, integer, null]
lifeCycle:
requestAcceptGraceTimeout: # @schema type:[string, integer, null]
graceTimeOut: # @schema type:[string, integer, null]
keepAliveMaxRequests: # @schema type:[integer, null]; minimum:0
keepAliveMaxTime: # @schema type:[string, integer, null]
测试发现依然无法推送。
我试图寻找k8s中的Traefik请求体的大小限制选项,但并没有找到相关配置项。
Traefik未发现问题,测试Ingress
Kubernetes的官方Ingress Controller是ingress-nginx,它可以根据Ingress资源中的nginx.ingress.kubernetes.io/proxy-body-size
注解来实现限制请求体的大小。考虑到很多第三方Ingress Controller都支持检测ingress-nginx的配置,Traefik可能也支持了这一限制,于是我添加了这一注解并进行了测试。
测试结果是,即使放宽了限制,推送依然失败。
修改Ingress无果,查看仓库自身的参数
于是接下来便想到了本地镜像库Harbor本身是否存在限制。
翻看了一遍Harbor官方Helm Chart的Values,试图找到有可能存在的大小限制选项,但只在S3存储和OSS存储中发现了分片大小的配置,还有上述ingress-nginx的注解配置。
Harbor的后端存储位于阿里云OSS,但是配置方式并非Harbor Chart提供的S3兼容存储或OSS存储方式(主要是因为多次尝试后发现push Layer会卡住,原因不明),而是使用了另一个开源的k8s-csi-s3项目作为集群存储类的CSI,在Harbor处仅仅简单配置了存储类(之前经过测试,push没问题)。
尝试搜索阿里云OSS是否存在请求体大小限制,发现限制为5GB,显然我推送的Layer不会有这么大。
这下可真是一头雾水了。
内网不稳定,怀疑网络层和传输层问题
经过上述的排查过程,在应用层的各种HTTP代理中没找到线索。
接着我某次偶然发现在内网的节点之间使用scp传输文件速度非常不稳定,一会儿跑满VPN带宽上线,一会儿又降到个位数KB/s,随后stall,于是我将目光转向网络层和传输层。
一直以来使用Softether VPN让我非常信任它,但是其他排查方向都没有眉目,不得不怀疑一下Softether VPN了。
要研究网络层和传输层问题,我决定先不测试k8s内的cilium网络组件,而是测试Softether VPN。一是因为cilium组件使用了eBPF技术,非常复杂,以我目前的知识难以入手;二是因为k8s的cilium网络组件乃至整个k8s网络是建立在集群Softether VPN内网之上的,如果问题出在底层的网络上,排查完毕后上层的问题也许就能迎刃而解。
测试网络层,使用ping
命令对内网的节点进行长时间互相测试,并未发现异常,延时都在正常范围内。
测试传输层,使用iperf
命令进行数据传输测试。
以下是对部分节点的iperf
测试,A节点作为iperf
服务端,B和E节点作为iperf
客户端。
客户端测试命令:
iperf3 -c <server_addr> -n 100M -P 8 # 使用默认TCP协议以8线程传输100M数据到服务端
内网测试
B节点测试的服务端显示过程:
B节点测试的客户端结果:
可以看到B节点的iperf测试比较不稳定,断断续续,有上百次的重传。
E节点测试的服务端显示过程:
E节点测试的客户端结果:
可以看到E节点的iperf测试非常不稳定,数据断断续续,有上万次重传,非常难绷。
公网测试
作为对比,测试下公网上(不经过Softether VPN)iperf的效果。
B节点测试的服务端显示过程:
B节点测试的客户端结果:
E节点测试的服务端显示过程:
E节点测试的客户端结果:
待更新
Comments 2 条评论
博主 Yiiong
哥会网络太强了😭
博主 zhangxinhui02
@Yiiong 不是哥们真有人关注我博客阿()