访问ingress nginx出现400报错
序言 在k8s中,使用的比较多就是ingress nginx了,如果你不仔细看一些配置信息,那么就会出现一些意想不到的报错。背景:当把nginx里面的服务迁移到ingress nginx之后,访问出现了400报错,如果是你,你会怎么来排查?400报错排查 1 收到问题当迁移完成之后,就有人报障说,访问全部出现出现400 bad request,第一时间看到这个状态码,那...
序言
在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 头取出来进行对比。
在进行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的默认配置。
如果能修改ingress的话,那么也可以将这一段配置去掉,也能解决问题,不过修改这种helm chart的配置超级麻烦,所以就不这么修改了。
风言风语
本来是不想理的问题,最后真正去解决的时候,发现忽然走到了死胡同,服务端返回的400,已经超出了ingress nginx的范畴了,还好最后找到了应用的人配合,才得到解决。
想想为啥没从日志里面看到对应后端的返回,因为粗心咯;再想想为啥构造的请求,居然还是成功的,一度怀疑curl命令进行构造的时候,没有将对应的header传过去,重新抓了下包,发现都传了,但是命令没有拼接最关键的header头。
解决了一个问题,毫无成就感,一个问题没解决,挫败感铺天盖地。。。
更多推荐
所有评论(0)