1、集群说明2、预备知识3、问题描述4、排查流程5、回顾总结html
firewalld 是 iptables 的前端控制器,用于实现持久的网络流量规则。前端
firewalld 自身并不具有防火墙的功能,而是和 iptables 同样须要经过内核的 netfilter 来实现,也就是说 firewalld 和 iptables 同样,他们的做用都是用于维护规则,而真正使用规则干活的是内核的 netfilter,只不过 firewalld 和 iptables 的结构以及使用方法不同罢了。网络
netfilter 有五链四表,说明以下。
五链:app
四表:curl
四个表的优先级由高到低的顺序为:raw → mangle → nat → filter,好比说 PRROUTING 链上,即有 mangle 表,也有 nat 表,那么先由 mangle 处理,而后由 nat 表处理。tcp
Linux 上的防火墙是由 netfilter 实现的,可是 netfilter 的功能不只仅只有“防火”,通常能够认为“防火”的功能只是 filter 表的功能。学习
了解上述知识后,咱们能够把数据包经过防火墙的流程总结为下图。
url
集群部署完成后,访问 VIP:PORT 遭到拒绝(Connection refused)。spa
直接访问 RS1:PORT 和 RS2:PORT 都可以正常访问 Nginx 服务(因为我未写入index.html,因此返回404页面是正常现象)。.net
① 关闭 DS 防火墙,未解决问题。恢复开启 DS 防火墙后,再尝试关闭 RS1 防火墙,RS1 服务正常返回,RS2 依旧是链接拒绝。
猜想 Client → DS 这条链路是正常的,问题出如今 DS → RS 这条链路上。
② 恢复开启 RS1 的防火墙,登录至 DS 机器上,使用命令ipvsadm -L -n
查看链接状态来验证猜测。
ipvsadm -L -n 命令结果小科普:
对于 TCP 协议而言,ActiveConn 列是活动链接数,也就是tcp链接状态的 ESTABLISHED ,而 InActConn 列是指除了 ESTABLISHED 之外的,全部的其它状态的 tcp 链接。
当前 InActConn 和 ActiveConn 均为0。
在 Client 端继续使用命令for i in {1..100}; do curl 10.1.61.82:80; sleep 0.5; done
循环请求 VIP:PORT,而后在 DS 上使用命令ipvsadm -L -n
再次查看链接状态。发现 InActConn 数值发生了改变,说明 DS 是收到了 Client 端的数据包的,ActiveConn 为0是由于 DS → RS 被拒,因此 tcp 链接未能创建。
目前已定位到数据包出现问题的链路是在 DS → RS ,OK,那就抓个包看看呗。
③ 在DS上使用命令tcpdump -i any host 10.1.62.105
截获 RS1 收到和发出的全部数据包(在 Client 依然用老方法循环请求 VIP:PORT ),能够看到 DS 发给 RS1 的数据包被 RS1 用一个协议为 ICMP 的数据包拒绝了。等等,这个数据包的内容咋这么眼熟(ICMP host prohibited),好像用 iptables 查看规则时见过。
④ 我立刻登录到RS1,直接用命令iptables --line -vnL INPUT
查看 INPUT 链中的规则(--line
可显示规则的编号,数据包在链中是顺着规则编号往下逐步匹配的;-v
显示详细信息;-n
不解析IP地址;-L
指定链名;不指定-t
默认显示 filter 表)。
能够看到第七条 REJECT 规则就是用 icmp-host-prohibited 做为数据包内容拒绝的。啊哈?DS 发给 RS1 的数据包被最后一条规则匹配到了?为何没被前面的规则处理掉?我不是开启了80端口吗?
⑤ 虽然一堆疑问,不过仍是先确认下 DS 发给 RS1 的数据包是否是真被第七条规则匹配处理了。这里我采用的方法是,在 Client 端循环请求 VIP:PORT 的先后分别用命令iptables --line -vnL INPUT
查看第七条规则的 pkts(该规则匹配到的数据包数量)数值是否发生了变化,果真 pkts 发生了增加,说明数据包真的是被第七条规则匹配到而且 REJECT 掉了。
额,我用命令iptables --line -vnL
查看了全部 Chain(链) 的规则,找到我开放80端口的那两条规则又确认了一下,发现 dport 是80,协议为 tcp 的那条规则 pkts 一直是0,并无变化(这条规则在 INPUT 链中是被第五条规则匹配的,规则虽然是在 IN_public_allow 链的,但了解过 iptables 自定义链相关知识后,就会明白这其实是一个调用链的关系:INPUT_ZONES → IN_public → IN_public_allow,从下图的每一个 Chain 的 target 也能看出来)。
再次确认下,这条规则源地址、目标地址、端口、协议等等都没有问题,并且最开始我也直接访问 RS1:PORT 确认过 Nginx 服务是没有问题的,能够正常返回,因此我怀疑从 DS → RS1 的数据包并非一个 tcp 包,因此没有被此规则匹配并处理。
⑥ 而后又返回去查了下 LVS-TUN 模式的数据包处理流程。
ipvs 工做在 INPUT 链,它在原有的 IP 报文外再次封装多一层 IP 头,内部 IP 头 (源地址为 CIP,目标 IP 为 VIP),外层 IP 头 (源地址为 DIP,目标 IP 为 RIP),而后将封装好的数据包从 DS 发往 RS 。
到这,我已经恍然大悟了,它确实不是一个 tcp 包,再翻到以前从 DS 上抓取 RS1 的数据包内容,能够看到 DS → RS1 的数据包协议为 ipip-proto-4。
⑦ 因此,处理方法也很明确了,放行这个 ipip 协议的数据包。个人处理方法是在 RS1 上使用命令iptables -t filter -I INPUT -p ipv4 -j ACCEPT
增长一条对全部协议类型为 ipip 的数据包ACCEPT的规则(这里的 prot 显示的 4 表明 ipv4 的协议号,想要查看协议名与协议号的对应关系能够在这里查找Protocol Numbers)。
记住必定要在 INPUT 链第七条以前,我这里是直接插入到了第一条,我以前看一篇博文上用的是-A INPUT
,这表示 append(追加) 一条规则,会出如今最后,这样设置的规则数据包根本就匹配不到,由于它已经被在你前面的那条REJECT规则匹配并拒绝掉了。
⑧ 最后咱们再从 Client 端请求验证一下规则是否生效,能够看到 RS1 已经正常返回了,且 RS1 上的第一条规则 pkts 也发生了增加,说明数据包已被匹配且正确处理。
RS2 也设置相同的过滤规则,而后再次验证,两台 RS 均正常返回,over。
不少搭建 LVS 集群的文章都会前置声明关闭防火墙或者使用iptables -F
命令将 iptables 规则清空,以避免发生通讯问题。实际上大多数状况下你确实能够这样作,可是万一辈子产环境就要开防火墙呢,万一设置的某几条 iptables 规则很是重要,你啪一条命令给人全清了,是否是得写个事故报告。
个人排查流程真的是像文章中同样如此顺利吗?其实并非,由于这个问题出现时,我既不清楚 iptables 相关知识(一两年前简单的看过,而后忘光了),也不清楚 ipvs 的工做原理,就是拿来主义,因此刚开始排查的时候和无头苍蝇同样,一顿瞎比操做,后来仍是滚回去补了 iptables 和 ipvs 的相关知识。因此其实排查流程中的第4步开始都已是次日的事了。
若是懂了 iptables 相关知识(五链四表、规则管理、匹配条件、扩展模块、自定义链等等)。清楚命令及命令结果中每一个参数的意思很是重要,像遇到此类防火墙问题,你均可以用文中的排查流程去走一遍,无非就是规则匹配问题。
分析网络问题,简单的抓包能够达到事半功倍的效果,配合 Wireshark 一块儿食用味道更佳。