首页 > 系统相关 >K8s为啥要启用bridge-nf-call-iptables内核参数?用案例给你讲明白

K8s为啥要启用bridge-nf-call-iptables内核参数?用案例给你讲明白

时间:2023-04-19 22:11:49浏览次数:45  
标签:iptables bridge frontend service panorama nf v2 ClusterIP

使用 kubernetes 遇到最多的 70%问题都可以归于网络问题,最近发现如果内核参数: bridge-nf-call-iptables设置不当的话会影响 kubernetes 中 Node 节点上的 Pod 通过 ClusterIP 去访问同 Node上的其它 pod 时会有超时现象,复盘记录一下排查的前因后因。

1、问题现象
集群环境为 K8s v1.15.9,cni 指定了 flannel-vxlan 跟 portmap, kube-proxy 使用 mode 为 ipvs

问题现象是,某个 Node 节点上的 pod 通过 service 访问其它服务时,有些能通,有些不通,不通的都提示 timeout

异常的请求:

$ curl -v http://panorama-v2-frontend-service.spring-prod.svc.cluster.local:8080
* Rebuilt URL to: http://panorama-v2-frontend-service.spring-prod.svc.cluster.local:8080/
* Trying 10.233.53.172...
* TCP_NODELAY set
# 这里一直等待直到超时
这个节点上的很多 pod 都存在这个问题, 其它节点未发现异常.

正常请求:

$ curl -v http://panorama-v2-frontend-service.spring-prod.svc.cluster.local:8080
* Rebuilt URL to: http://panorama-v2-frontend-service.spring-prod.svc.cluster.local:8080/
* Trying 10.233.53.172...
* TCP_NODELAY set
* Connected to panorama-v2-frontend-service.spring-prod.svc.cluster.local (10.233.53.172) port 8080 (#0)
> GET / HTTP/1.1
> Host: panorama-v2-frontend-service.spring-prod.svc.cluster.local:8080
> User-Agent: curl/7.52.1
> Accept: */*
>
< HTTP/1.1 200 OK
2、排查过程
先对异常 Node 进行排查,因为其它节点是正常的,通过对异常 Node 的网络、kube-proxy、 iptables、ipvs 规则、kubelet 等排查后未发现有可疑的地方,就暂时排除嫌疑了。

第二个可疑的是 DNS, coreDNS 负责对 service 解析成 ClusterIP, 在出问题的 Node 上经过多次测试均能正确解析,coreDNS 排除嫌疑。

可疑的地方都筛了一遍,无果, 那就只能再从现象来发现看看有没有相同点。

首先,访问路径为:Service – > ClusterIP – > PodIP

对 service 访问异常,coreDNS 已经被排除了,那先绕过 service,直接使用 ClusterIP 访问呢? 测试后现象依旧。另外关注公号“终码一生”,回复关键词“资料”,获取视频教程和最新的面试资料!

那再绕过 ClusterIP,直接使用 PodIP 呢? Bingo,之前会出问题的访问都是正常的了。

那么问题就出在 CluterIP – > PodIP 上, 那么又有以下可能:

ClusterIP 没有正确转发到 PodIP 上可能导致超时

如果正确转发,响应没有返回也可能导致超时

第一种可能性很容易排查,之前已经确认了 ipvs 规则、iptables 规则都是没有问题的,且通过 ClusterIP 发起的请求可以到达 PodIP 上, 基本就排除了可能性一

另外,对比正常跟异常请求会发现,异常的请求原 Pod 跟目标 pod 都是在同一个 Node 上,而正常的请求则处于不同的 Node,会是这个影响吗?

上面的可能性二,只能祭出抓包神器了tcpdump, 通过抓包发现(抓包过程见文未)会发现请求中出现了Reset

那么问题转换一下: 为什么相同 Node 上 podA 通过 service/ClusterIP 访问 PodB 响应会不返回呢,而通过 PodIP 访问就没问题?

补充一句就是,相同 Node 上的 pod 相互访问是不需要经过 Flannel 的,因此 Flannel 可以排除嫌疑

so, 问题在哪?

回到 tcpdump 的抓包数据, 可以发现,响应的数据没有按照请求的路径返回,嗯,Interesting

3、罪魁祸首
不管是 iptables 还是 ipvs 模式,Kubernetes 中访问 service 都会进行 DNAT,将原本访问 ClusterIP:Port 的数据包 DNAT 成 service 的某个 Endpoint (PodIP:Port),然后内核将连接信息插入 conntrack 表以记录连接,目的端回包的时候内核从 conntrack 表匹配连接并SNAT,这样原路返回形成一个完整的连接链路.

 

从 tcpdump 看到请求被 reset 了, 没错, bridge-nf-call-iptables(如果是 ipv6 的话则是net.bridge.bridge-nf-call-ip6tables)参数

但是不对,这个参数 linux 默认开启的呢?难道是有人修改了么?

使用命令查看该参数是否开启:

$ cat /proc/sys/net/bridge/bridge-nf-call-iptables
# 0
返回 0,说明确实没有开启(后来被证实是被同事修改了),那这个参数是如何影响的返回路径的呢?

那就不得不说linux bridge了!

虽然 CNI 使用的是 flannel, 但 flannel 封装的也是 linux bridge,linux bridge 是虚拟的二层转发设备,而 iptables conntrack 是在三层上,所以如果直接访问同一网桥内的地址(ip 同一网段),就会直接走二层转发,不经过 conntrack:

结合上面的图来看,同 Node 通过 service 访问 pod 的访问路径如下:

PodA 访问 service, 经过 coreDNS 解析成 Cluster IP,不是网桥内的地址(ClusterIP 一般跟 PodIP 不在一个网段),走 Conntrack,进行 DNAT,将 ClusterIP 转换成 PodIP:Port

DNAT 后发现是要转发到了同节点上的 PodB,PodB 回包时发现目的 IP(此时是 PodA 的 IP) 在同一网桥上(PodA 与 PodB 的 IP 段一致),就直接走二层转发了,不会去调 conntrack,这样就导致回包时没有原路返回

没有返回包就导致请求方一直等直到超时退出.

这样也解释了为何访问在其它节点的应用的 ClusterIP 没有问题,因为目标 PodIP 与源 PodIP 不在同一个网段上,肯定要走 conntrack.

4、问题解决
总述,开启参数后问题解决

$ echo "net.bridge.bridge-nf-call-iptables=1" >> /etc/sysctl.conf
$ echo "net.bridge.bridge-nf-call-ip6tables=1" >> /etc/sysctl.conf

$ sysctl -p /etc/sysctl.conf
5、linux conntrack
关于 conntrack 其实也是个值得好好研究一番的知识点, 各个发行版都有工具可以看到 conntrack 里的记录,格式如下:

$ conntrack -L

tcp 6 119 SYN_SENT src=10.224.1.34 dst=10.233.53.172 sport=56916 dport=8080 [UNREPLIED] src=10.224.1.56 dst=10.224.1.34 sport=8080 dport=56916 mark=0 use=1
那个著名的DNS 5s timeout[1]的问题就跟 conntrack 机制有关,由于篇幅有限,就不在这里展开.

6、tcpdump
在容器中的抓包命令

$ tcpdump -vvv host 10.224.1.34 or 10.233.53.172 or 10.224.1.56
其中的三个 ip 分别对应 podA IP, podB 的 ClusterIP, podB 的 PodIP

这里由于篇幅的关系,只保存有关键信息,同时使用注释是作者加入的,方便理解.

对于异常请求的 tcpdump,如下:

# podA 请求 PodB
panorama-frontend-deploy-c8f6fd4b6-52tvf.45954 > panorama-v2-frontend-service.spring-prod.svc.cluster.local.8080: Flags [S], cksum 0x4cc5 (incorrect -> 0xba1b), seq 1108986852, win 28200, options [mss 1410,sackOK,TS val 1345430037 ecr 0,nop,wscale 7], length 0
# 10-224-1-56是PodB的podIP, 这里省略了解析过程,可以看到返回数据给PodA
10-224-1-56.panorama-v2-frontend-service.spring-prod.svc.cluster.local.8080 > panorama-frontend-deploy-c8f6fd4b6-52tvf.45954: Flags [S.], cksum 0x1848 (incorrect -> 0x99ac), seq 3860576650, ack 1108986853, win 27960, options [mss 1410,sackOK,TS val 2444502128 ecr 1345430037,nop,wscale 7], length 0
# 重点: podA直接reset了请求.
panorama-frontend-deploy-c8f6fd4b6-52tvf.45954 > 10-224-1-56.panorama-v2-frontend-service.spring-prod.svc.cluster.local.8080: Flags [R], cksum 0xb6b5 (correct), seq 1108986853, win 0, length 0
最后会发现 PodA 给 PodB 发送了个R Flags, 也就是reset, 就是因为当 PodB 返回握手确认给到 PodA,PodA 根本不认识这个请求,所以直接给 reset 掉了, 三手握手都没有建立,this is why!

而对于net.bridge.bridge-nf-call-iptables=1的正常请求的 tcpdump 如下:

# 能看到正常的三次握手, 这里省略
# 开启传输数据
panorama-frontend-deploy-c8f6fd4b6-52tvf.36434 > panorama-v2-frontend-service.spring-prod.svc.cluster.local.8080: Flags [P.], cksum 0x4d3c (incorrect -> 0x6f84), seq 1:128, ack 1, win 221, options [nop,nop,TS val 1346139372 ecr 2445211463], length 127: HTTP, length: 127
GET / HTTP/1.1
Host: panorama-v2-frontend-service.spring-prod.svc.cluster.local:8080
User-Agent: curl/7.52.1
Accept: */*

panorama-v2-frontend-service.spring-prod.svc.cluster.local.8080 > panorama-frontend-deploy-c8f6fd4b6-52tvf.36434: Flags [.], cksum 0x4cbd (incorrect -> 0xe8a6), seq 1, ack 128, win 219, options [nop,nop,TS val 2445211463 ecr 1346139372], length 0

panorama-v2-frontend-service.spring-prod.svc.cluster.local.8080 > panorama-frontend-deploy-c8f6fd4b6-52tvf.36434: Flags [P.], cksum 0x4dac (incorrect -> 0x0421), seq 1:240, ack 128, win 219, options [nop,nop,TS val 2445211463 ecr 1346139372], length 239: HTTP, length: 239
HTTP/1.1 200 OK
Server: nginx/1.17.1
Date: Wed, 18 Aug 2021 15:10:17 GMT
Content-Type: text/html
Content-Length: 1540
Last-Modified: Fri, 09 Jul 2021 06:36:53 GMT
Connection: keep-alive
ETag: "60e7ee85-604"
Accept-Ranges: bytes
相信这个请求路径还是很清晰的,就不再啰嗦.

7、结语
禁用net.bridge.bridge-nf-call-ip6tables这个参数当然也有好外,那就是考虑同网段的 IP 访问没必要走 conntrack,一定程度有助于性能。

kubernetes 的官方文档[2]中明确提及 Node 节点上需要开启这个参数,不然碰到各种诡异的现象也只是时间问题,所以还是不要随意调整。

以防后患的话可以对该参数是否开启进行监控,防止被人误修改。
————————————————
版权声明:本文为CSDN博主「终码一生」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/best_luxi/article/details/121823983

标签:iptables,bridge,frontend,service,panorama,nf,v2,ClusterIP
From: https://www.cnblogs.com/cheyunhua/p/17334812.html

相关文章

  • Plugin execution not covered by lifecycle configuration
    <build><pluginManagement><plugins><!--Thisplugin'sconfigurationisusedtostoreEclipsem2esettingsonly.IthasnoinfluenceontheMavenbuilditself.-->......
  • kubectl apply -f --record 是否将当前创建对象创建命令保存到Annotation注解中中。
    kubectlcreate-ftomcat-app1.yaml--save-config--recordkubectlapply-ftomcat-app1.yaml--record#推荐命令 --record  #是否将当前对象创建命令保存至Annotation中,布尔型数据(true或false) --save-config  #是否将当前对象配置信息保存至......
  • BNF语法表示方式
    巴科斯范式:以美国人巴科斯(Backus)和丹麦人诺尔(Naur)的名字命名的一种形式化的语法表示方法,用来描述语法的一种形式体系,是一种典型的元语言。符号含义如下:"在双引号中的字代表字符本身。A::=B表示被定义为的意思。[A]方括号中包含的为可选项。A|B竖线表示其左右两边只能选一......
  • 【C#新手入门一】winform实现QQ登录窗口
    闲来无事,打算写一系列winform入门相关的小软件,算是对自己技术的一个复习和备忘,也希望能帮助刚入门的萌新(可能也帮不到,因为没有注释)第一期先用winform最大限度的还原QQ的登录界面,下图左侧是仿真的,右侧是QQ的界面,很明显能看出来高仿的和正版的区别,哈哈! 这是效果展示接下来......
  • unFormal
    1、static作用-在函数体内,一个被声明为staic的变量在被调用时保持值不变-在模块内(函数体外),一个被声明为static的变量能被模块内的函数调用,模块外的函数不能调用,它是一个本地的全局变量-一个被声明为static的函数,只能被模块内的其他函数调用2、对数据库日期字段排序的关键字是......
  • yem仓库和NFS
    拓扑图:推荐步骤:在Centos01挂载操作系统光盘,安装vsftpd服务启动服务设置开机自动启动,将系统光盘数据移动到ftp的默认根目录,配置本地yum为ftp访问,安装nfs服务,创建nfs根目录设置网站主页内容为自己名字全拼.com,配置nfs允许Centos03访问nfs共享的数据,在Centos02、Centos03配置ftp的yum......
  • OpenFeign组装请求头Header
    组装单个Header参数@RequestHeader("Authorization")Stringtoken组装多个Header参数@PostMapping(value="/a/b",headers={"Content-Type=application/json","a=AAAAAA","b=BBBBB"})ObjectcreateSth(@RequestBodyModel......
  • Spring源码分析——BeanFactory体系之接口详细分析
    Spring的BeanFactory的继承体系堪称经典。这是众所周知的!作为Java程序员,不能错过!前面的博文分析了Spring的Resource资源类Resouce。今天开始分析Spring的IOC部分。众所周知,IOC是Spring框架最迷人的地方。它最重要的接口,就是BeanFactory了。BeanFactory有着庞大的继承、实现......
  • iptables命令常用规则汇总
    iptables非常强大,但是参数选项多,学习成本较高。本文将常用的iptables的命令进行汇总,在关键时刻方便拿来即用。iptables的四表五链iptables的四表五链是指iptables中的四个表和五个链。四个表分别是:filter表:用于过滤数据包,控制网络流量。nat表:用于对数据包进行地址转换,实现......
  • adb(Android Debug Bridge)安装使用教程
    参考:https://www.cnblogs.com/lsdb/p/9438215.html一、说明adb的db是debugbridge而不是和gdb一样指debug,这意思是说adb不能像gdb那样能一步步调试代码,但可以启到一些类似调试的功能。下面就针对这些功能进行介绍,本文根据官方文档“http://adbshell.com/commands”整理而成。......