做运维和后端开发的,最怕的就是线上出Bug,特别是深夜出Bug,睡得正香被电话叫醒,那种感觉真的很难受。上周我就遇到了一次,线上Kubernetes集群出了个Bug,导致部分服务异常,访问超时,用户投诉量暴增,我从晚上十点开始排查,一直排查到第二天早上六点,整整一夜,最后终于找到了问题的根源,是一个很低级但是很隐蔽的配置问题。今天就来记录一下这次排查Kubernetes Bug的经历,聊聊排查过程、根本原因,以及我们总结的经验教训,希望能给大家一些警示,避免踩同样的坑。
一、故障发生:部分服务访问超时
那天是个周四,本来是个很平常的日子,晚上我加了一会儿班,九点多才回家,洗了个澡,正准备睡觉,十点多的时候,手机突然响了,是运维同事打来的,说线上出问题了,部分服务访问超时,用户投诉量在快速上升,让我赶紧起来看看。
我当时心里一紧,赶紧打开电脑,连上VPN,登录线上监控系统查看情况。首先看监控,发现部分接口的响应时间在飙升,从平时的几百毫秒涨到了几秒甚至十几秒,而且错误率也在上升,很多请求都超时了。但是奇怪的是,不是所有服务都有问题,只有一部分服务有问题,另一部分服务完全正常,而且有问题的服务,也不是完全不可用,是有时候正常,有时候超时,很不稳定。
当时第一反应是,是不是服务器负载太高了?我赶紧去看服务器的CPU、内存、网络、磁盘IO,发现都很正常,没有负载过高的情况。那是不是数据库或者Redis出问题了?我又去看数据库和Redis的监控,发现也都正常,连接数、响应时间、错误率都正常,没有问题。
那是不是网络出问题了?我又去看网络监控,发现网络带宽、延迟、丢包率都正常,没有网络故障。这就奇怪了,服务器、数据库、Redis、网络都正常,但是部分服务就是访问超时,而且时好时坏,很不稳定。
这时候用户投诉还在增加,领导也在群里问什么时候能修好,当时压力真的很大,但是又不能慌,只能硬着头皮继续排查。
二、排查过程:一步步缩小范围
冷静下来之后,我开始系统性地排查,一步步缩小范围。
首先,我找了一个出问题的服务,手动调用它的接口,看看具体是什么情况。手动调用之后,发现有时候能正常返回,有时候就超时,超时的时间不一定,有时候几秒,有时候十几秒,没有规律。而且,同一个接口,有时候调用正常,有时候调用超时,完全随机,这就更奇怪了。
然后,我进入这个服务的Pod里面,看服务的日志,发现服务本身没有报错,请求都正常处理了,响应时间也很短,几百毫秒就处理完了,但是为什么外面调用就超时呢?这说明问题不在服务本身,服务处理请求是正常的,问题应该在请求的链路上,也就是从客户端到服务的这段链路上,某个环节出了问题。
请求的链路是这样的:用户请求 → 负载均衡 → Ingress → Service → Pod。那问题可能出在Ingress、Service、或者Pod网络上。
我先看Ingress的日志,发现Ingress也没有报错,请求都正常转发了,但是有些请求的响应时间很长,说明Ingress转发请求之后,等了很久才收到响应,或者根本没收到响应,超时了。这说明问题在Ingress到Pod的这段链路上。
然后,我看Service的配置,Service的配置是正常的,Selector也对,Endpoints也正常,对应的Pod IP都在,没有问题。那问题应该在Pod网络上,也就是Kubernetes的网络插件出问题了。
我们用的网络插件是Flannel,用的是VXLAN模式。我去看Flannel的日志,发现Flannel也没有报错,运行正常。我又去看节点上的网络配置,路由表、ARP表、VXLAN设备,都看起来正常。
这时候我有点懵了,所有组件看起来都正常,但是就是部分服务访问超时,时好时坏。这时候已经凌晨一点多了,排查了三个多小时,还没找到问题,心里很着急,但是又不能放弃。
这时候,我突然想到,是不是只有部分节点上的Pod有问题?因为不是所有服务都有问题,只有一部分服务有问题,会不会是这些服务的Pod刚好调度到了某些有问题的节点上?
想到这里,我赶紧去看那些出问题的服务的Pod都在哪些节点上,然后和正常的服务的Pod所在的节点对比。一对比,果然发现了问题!出问题的服务的Pod,都在某几个特定的节点上,而正常的服务的Pod,都在其他节点上。也就是说,问题不是出在服务上,而是出在节点上,某几个节点有问题,调度到这几个节点上的Pod,都会出现访问超时的问题,而调度到其他节点上的Pod,都正常。
这个发现很重要,一下子就把范围缩小到了那几个有问题的节点上。我赶紧登录到其中一个有问题的节点上,仔细排查这个节点的网络配置。
一开始,还是没发现什么问题,路由表、ARP表、VXLAN设备、iptables规则,看起来都正常。但是当我用ping命令测试这个节点到其他节点的Pod网络连通性的时候,发现了问题!这个节点ping其他节点上的Pod,有时候能通,有时候丢包,丢包率很高,大概30%左右,而且延迟也很高,有时候几毫秒,有时候几百毫秒,很不稳定。而正常的节点,ping其他节点的Pod,都是0丢包,延迟也很稳定,几毫秒。
这就说明,问题确实出在这几个节点的网络上,这几个节点的Pod网络不稳定,丢包率高,延迟高,所以调度到这几个节点上的服务,访问的时候就会超时,时好时坏。
那为什么这几个节点的网络会不稳定呢?我继续排查,对比有问题的节点和正常的节点的网络配置,一项一项对比。对比了很久,终于发现了问题!有问题的节点上,MTU(最大传输单元)的配置不对!
正常的节点上,物理网卡的MTU是1500,VXLAN设备的MTU是1450(因为VXLAN封装需要50字节的开销),Pod里面的网卡的MTU也是1450。但是有问题的节点上,物理网卡的MTU是1500,但是VXLAN设备的MTU被配置成了1500,Pod里面的网卡的MTU也是1500!
这就是问题的根源!因为VXLAN封装需要50字节的开销,如果VXLAN设备的MTU是1500,那么加上VXLAN封装的50字节,整个数据包的大小就是1550字节,超过了物理网卡的MTU 1500,就会被分片。而UDP分片(VXLAN用的是UDP)是很不可靠的,只要有一个分片丢了,整个数据包就丢了,而且分片的重组也会增加延迟,所以就会出现丢包率高、延迟高、时好时坏的情况。
而且,为什么只有部分请求超时呢?因为小的数据包(小于1450字节)不需要分片,就能正常传输,所以访问正常;大的数据包(大于1450字节)需要分片,就会丢包或者延迟高,所以访问超时。这就解释了为什么有时候正常,有时候超时,因为请求和响应的大小不一样,小的正常,大的超时。
找到问题之后,修复就简单了,把这几个有问题的节点上的VXLAN设备和Pod网卡的MTU改成1450,和正常的节点一致,然后重启Flannel和有问题的Pod,网络马上就恢复正常了,丢包率降到了0,延迟也稳定了,服务访问也正常了,错误率和响应时间都降下来了。
从故障发生到修复,一共花了八个多小时,虽然最后修好了,但是影响很大,那几个小时部分服务不稳定,用户体验很差,还流失了一些用户。
三、根本原因:配置不一致,变更不规范
这次故障看起来是Kubernetes的网络问题,但是深入分析之后,发现根本不是Kubernetes本身的问题,而是最基础的配置问题,是节点配置不一致,变更不规范导致的。
那为什么这几个节点的MTU配置不对呢?我去查了一下,发现这几个节点是上周扩容的时候新上线的节点,上线的时候,运维同事用的是旧的初始化脚本,那个脚本里的MTU配置是1500,没有考虑VXLAN的开销。而之前的节点,用的是新的初始化脚本,MTU配置是1450,是对的。因为初始化脚本更新了,但是旧的脚本没有删除,新节点上线的时候用了旧的脚本,就导致了MTU配置错误。
而且,新节点上线的时候,没有做完整的网络测试,只是看节点能正常加入集群,Pod能正常启动,就以为没问题了,没有测试Pod网络的连通性、丢包率、延迟、MTU等,所以这个配置错误没有及时发现,直到线上出了问题才排查出来。
总结一下,这次故障的根本原因有几个:
第一,配置管理不规范。初始化脚本有新旧两个版本,没有统一管理,旧的脚本没有及时删除,导致新节点上线的时候用了旧的脚本,配置错误。这是最根本的原因。
第二,节点上线流程不规范。新节点上线的时候,没有做完整的测试,特别是网络测试,只是简单看了一下节点状态和Pod状态,没有测试Pod网络的连通性、丢包率、延迟、MTU等,导致配置错误没有及时发现。
第三,监控不完善。没有节点网络质量的监控,比如Pod网络的丢包率、延迟、MTU一致性等,节点网络出了问题,不能及时发现,直到影响了业务,用户投诉了才知道。如果有网络质量监控,节点一上线就能发现网络异常,就不会导致线上故障了。
第四,缺乏配置一致性检查。没有定期检查所有节点的配置是否一致,比如MTU、内核参数、系统配置等,导致部分节点配置错误,长期没有发现。
这些都是最基础的运维和配置管理问题,和Kubernetes本身没有关系,但是就是这些基础问题,导致了一次严重的线上故障。这也说明,不管技术架构多么先进,基础工作做不好,一样会出问题,基础不牢,地动山摇。
四、经验教训和改进措施
故障修复之后,我们做了详细的复盘,总结了经验教训,并且做了一系列的改进措施,避免类似的问题再次发生。
第一,统一配置管理。我们把所有的初始化脚本、配置文件都统一管理起来,用配置管理工具(比如Ansible)统一管理,所有节点的配置都从同一个配置中心拉取,保证配置一致。旧的脚本和配置文件及时删除,避免误用。而且配置变更的时候,要经过评审,不能随便改,改了之后要同步更新所有节点。
第二,规范节点上线流程。新节点上线的时候,必须做完整的测试,包括操作系统配置检查、网络测试(连通性、丢包率、延迟、MTU、带宽)、存储测试、容器运行时测试、Kubernetes组件测试等,所有测试都通过了,才能正式接入流量,上线使用。而且上线之后,要密切监控24小时,确认没有问题。
第三,完善监控告警。增加了节点网络质量的监控,包括Pod网络的丢包率、延迟、MTU一致性、VXLAN设备状态等,有异常马上告警,不用等影响业务才发现。还增加了配置一致性检查,定期检查所有节点的配置是否一致,有不一致的马上告警。
第四,增加混沌工程测试。我们定期做混沌工程测试,比如随机杀掉节点、随机杀掉Pod、模拟网络丢包、模拟网络延迟等,测试系统的容错能力和恢复能力,提前发现潜在的问题,而不是等线上出了问题才发现。
第五,完善故障排查手册。我们把这次故障的排查过程、原因、解决方案都记录下来,整理成故障排查手册,以后遇到类似的问题,可以快速定位和解决,不用再花几个小时排查。而且,我们还整理了Kubernetes常见故障的排查手册,包括网络问题、存储问题、Pod问题、节点问题等,方便运维和开发人员快速排查问题。
第六,加强团队培训。我们组织了Kubernetes网络原理和故障排查的培训,让团队的每个人都了解Kubernetes的网络原理,掌握常见网络问题的排查方法,这样出了问题,大家都能参与排查,而不是只靠少数几个人。
经过这些改进之后,我们的Kubernetes集群稳定了很多,再也没有出过类似的配置不一致导致的故障。而且整个团队的运维意识和故障排查能力也提升了很多,大家都认识到了基础运维和配置管理的重要性。
五、Kubernetes网络问题排查的一些经验
通过这次故障,我也总结了一些Kubernetes网络问题排查的经验,分享给大家,希望能帮助大家更快地排查网络问题。
1. 先定位问题范围
遇到网络问题,首先要定位问题范围,是所有服务都有问题,还是部分服务有问题;是所有节点都有问题,还是部分节点有问题;是入站有问题,还是出站有问题;是完全不通,还是时好时坏。把问题范围定位清楚了,就能大大缩小排查范围,提高排查效率。
2. 从Pod到节点,从节点到集群,逐层排查
Kubernetes的网络是分层的,Pod里面有网卡,节点上有虚拟设备(VXLAN、bridge等),节点之间有物理网络,还有Service、Ingress等。排查网络问题的时候,要从内到外,逐层排查,先看Pod里面的网络配置,再看节点上的虚拟网络设备,再看物理网络,再看Service和Ingress,一层一层排查,总能找到问题。
3. 善用基础网络工具
排查网络问题,要善用基础的网络工具,比如ping、traceroute、mtr、tcpdump、wireshark、ip、ifconfig、route、arp、iptables等,这些工具虽然基础,但是非常有用,大部分网络问题都能用这些工具定位到。比如这次的问题,就是用ping测试发现了丢包,然后对比MTU配置发现了问题。
4. 注意MTU问题
MTU问题是Kubernetes网络中很常见但是很隐蔽的问题,特别是用了VXLAN、IPIP等隧道封装的网络插件,因为封装有开销,所以虚拟设备的MTU要比物理网卡的MTU小,不然就会分片,导致丢包和延迟。如果遇到时好时坏、大请求超时小请求正常的情况,一定要检查MTU配置,很可能就是MTU的问题。
5. 对比正常和异常的配置
排查问题的时候,一个很有效的方法就是对比,把有问题的节点/ Pod的配置,和正常的节点/ Pod的配置对比,一项一项对比,往往就能发现问题。这次的问题就是通过对比有问题的节点和正常的节点的MTU配置发现的。很多问题都是配置不一致导致的,对比是最快的定位方法。
6. 看日志,也要看监控
排查问题的时候,不要只看日志,也要看监控,日志能告诉你发生了什么错误,监控能告诉你指标的变化趋势,两者结合起来,才能更快地定位问题。而且,很多问题日志里没有报错,但是监控指标会有异常,比如这次的问题,所有组件的日志都没有报错,但是网络丢包率和延迟的监控指标有异常,通过监控就能发现问题。
六、写在最后
线上出了个Kubernetes的Bug,我排查了一夜。
以上就是我们这次Kubernetes网络故障的完整排查经历,从故障发生、排查过程、根本原因,到经验教训和改进措施,都做了详细的记录。这次故障虽然影响很大,排查了一夜,很辛苦,但是也给我们上了深刻的一课,让我们认识到了基础运维和配置管理的重要性,也让我们的团队成长了很多。
很多人觉得Kubernetes很复杂,出了问题很难排查,但是实际上,大部分Kubernetes的问题,都不是Kubernetes本身的问题,而是最基础的配置问题、网络问题、运维问题。只要我们把基础工作做好,配置统一,流程规范,监控完善,测试充分,很多问题都是可以避免的。就算出了问题,只要掌握了正确的排查方法,从基础开始,逐层排查,对比分析,也能很快定位和解决。
技术是不断发展的,从物理机到虚拟机,再到容器和Kubernetes,技术越来越先进,越来越复杂,但是不管技术怎么变,基础都是最重要的。网络、操作系统、配置管理、运维流程,这些基础的东西,不管用什么技术架构,都是最重要的,基础打牢了,才能用好先进的技术,才能让系统稳定运行。
希望我们的这次故障经历能给大家一些警示,做Kubernetes运维和开发的朋友,一定要重视基础配置和运维流程,不要只关注上层的功能和架构,基础工作做好了,系统才能稳定,才能少出故障,少熬夜。
最后用一句话结尾:"基础不牢,地动山摇;细节决定成败,规范保障稳定。"愿我们都能重视基础,做好细节,规范流程,让系统稳定运行,少出Bug,少熬夜。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录