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 一塊兒食用味道更佳。