序言

    在k8s中,使用的比较多就是ingress nginx了,如果你不仔细看一些配置信息,那么就会出现一些意想不到的报错。

    背景:当把nginx里面的服务迁移到ingress nginx之后,访问出现了400报错,如果是你,你会怎么来排查?

400报错排查

    1 收到问题

    当迁移完成之后,就有人报障说,访问全部出现出现400 bad request,第一时间看到这个状态码,那么就认为是客户端的问题,毕竟4xx的报错都是客户端的问题。

    先查看了一个error log信息,发现没有对应的报错信息,再去看看access log,好像也没看到有用的信息。(此处有坑)

    接着又收到了其他的反馈:当使用nginx的容器进行代理的时候,请求服务都是正常的;但是一旦请求经过ingress nginx,那么全部报错400

    2 抓包

        这种进行对比的结果就很烦躁了,没迁移之前是好的,迁移之后是坏的,那说明问题大概率在ingress nginx上面,但是并不知道问题出在哪里。

        当没有头绪的时候,就只能抓包了,从而对ingress nginx的pod进行了抓包。

tcpdump -w 400.pcap

        在进行抓包的时候,还是比较喜欢直接抓所有的包,虽然在查看结果的时候,要从无数个包里面进行过滤,但是既然抓了,那就抓全一点。

        当在这种反向代理场景进行抓包的时候,如果进行ip或者其他的过滤,很可能抓的包不全,一个方面是客户端与ingress nginx的连接,一个是ingress nginx对后端的连接,有的时候还要把两个连接串起来进行分析,抓包的时候,注意包的大小,因为一不小心,磁盘就会被打爆了。

        在抓包开启之后,就要进行模拟命令了,一个是正常的请求,一个是不正常的请求

正常的请求,会返回200的响应码,可以请求一个特殊的url,便于找包
curl upsteam_server_ip/health
非正常请求的,会返回400的响应码
curl ingress_nginx_pod_ip/health

    包抓完后,就可以下载到本地进行分析了。

    3 分析包

        分析包的时候,直接ctrl + f,和普通的搜索一样,可以输入url里面的关键字来进行搜索,也就是上面的health,从而能找到两个对应的包,然后右键,选择follow http steam,从而可以看到整个包的信息,从而把两个连接的http 头取出来进行对比。

f3e384a653e699d59921a9c31edd2bc9.png

        在进行400分析的时候,可以看到异常的请求中,header头多了如下的信息:

X-Forwarded-For
X-Forwarded-Proto
X-Forwarded-Port
X-Forwarded-Host
X-Real-IP

        从这个信息看起来,肯定是这些header头导致的,那么就构造一个请求,将请求正常的加上这些头直接请求后端,看是否能正常响应

curl upsteam_server_ip/health -H "X-Real-IP:xx"
 -H "X-Forwarded-Port:xx" -H "X-Forwarded-Proto:xx"
  -H "X-Forwarded-For:xx"

        发送请求之后,发现依旧是正确的响应,这。。。莫非是玄学,百思不得其解(此处有坑)。

        没有办法,只能再次查看下异常的请求包,具体查看ingress nginx与后端的连接情况,发现ingress nginx把请求已经发送了后端,但是后端直接返回了一个400,那么说明是后端也就是服务端返回的,从而判断可能是服务端的问题。

        4 查看服务端日志

        拉服务端的人一起来看,发现是一个python的代码,里面用的是django的框架,然后查看对应的日志信息,发现了具体的报错信息:

Invalid HTTP_HOST header: '127.0.0.1:8000,127.0.0.1'.
 The domain name provided is not valid according
  to RFC 1034/1035.

        看到这个报错,那么就肯定了是host的header头出了问题,进行了header头的拼接,正好有人对python比较熟悉,从而修改了这段验证的逻辑,再次进行请求,就都变成了正常响应,从而问题解决。‍

        5 误区

  • 查看access log的时候,没有细看,从而没看到是upsteam_status也为400,并且具有upsteam_server,还有各种和后端连接时间,响应时间,从而未能及时判断是后端返回的400

  • 在抓包的时候,构造请求的时候,所有的参数都加上了,但是唯独没加上那个导致有问题的header头X-Forwarded-Host,从而未能判断是这个header头导致的400

  • 抓包不能解决一切问题,抓包的重点在于找到是谁发送的400响应,也就是谁发送的,那么就谁有问题,在看reset包的时候,也是这样,重点找到源头

  • 最大的问题:在看到400报错的时候,理都不想理,因为这都是客户端的问题,和我的配置有个毛的关系

  • 迁移之前是好的,迁移之后是坏的,心态容易爆炸,这两玩意儿不是一样的吗?其实并不是,在nginx的默认配置中,这些头基本上都是不传的,而在ingress nginx中,这些头默认都是传的,是ingress nginx的默认配置。

59fc7e53d3a0e1e4d8a1d5560e48457e.png

f911ddf7d0646bf3b3d390e78e3175f1.png

如果能修改ingress的话,那么也可以将这一段配置去掉,也能解决问题,不过修改这种helm chart的配置超级麻烦,所以就不这么修改了。

风言风语

    本来是不想理的问题,最后真正去解决的时候,发现忽然走到了死胡同,服务端返回的400,已经超出了ingress nginx的范畴了,还好最后找到了应用的人配合,才得到解决。

    想想为啥没从日志里面看到对应后端的返回,因为粗心咯;再想想为啥构造的请求,居然还是成功的,一度怀疑curl命令进行构造的时候,没有将对应的header传过去,重新抓了下包,发现都传了,但是命令没有拼接最关键的header头。

    解决了一个问题,毫无成就感,一个问题没解决,挫败感铺天盖地。。。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐