1. 程式人生 > >Kubernetes1.2如何使用iptables

Kubernetes1.2如何使用iptables

fin replace 功能 net 期待 ipc 不存在 ner containe

轉:http://blog.csdn.net/horsefoot/article/details/51249161

本次分析的kubernetes版本號:v1.2.1-beta.0。
Kubernetes中kube-proxy組件負責維護NODE節點上的防火墻規則和路由規則,Kube-proxy有兩種實現方式,一種是通過iptables,一種是通過userspace,在1.2中將使用iptables作為首選,可以大幅提升性能,下面看看kube-proxy組件是如何操作iptables的。
kube-proxy要求NODE節點操作系統中要具備/sys/module/br_netfilter文件,而且還要設置bridge-nf-call-iptables=1,如果不滿足要求,那麽kube-proxy只是將檢查信息記錄到日誌中,kube-proxy仍然會正常運行,但是這樣通過Kube-proxy設置的某些iptables規則就不會工作。
在源代碼中有檢查iptables版本是否低於1.4.11的校驗,如果iptables版本低於1.4.11,那麽不能使用-C/–check這個參數,這樣可以保證kube-proxy對iptables版本的向下兼容性。
Iptables默認的數據包流向圖如下圖所示:
技術分享


在iptables模式下,kube-proxy使用了iptables的filter表和nat表,並且對iptables的鏈進行了擴充,自定義了KUBE-SERVICES、KUBE-NODEPORTS、KUBE-POSTROUTING和KUBE-MARK-MASQ四個鏈,另外還新增了以“KUBE-SVC-”和“KUBE-SEP-”開頭的數個鏈。
在iptables表中,通過iptables-save可以看到在filter表和nat表中創建好的這些鏈,下面是示例:
技術分享
Kube-proxy配置iptables的過程通過syncProxyRules函數來執行的,首先在filter表和nat表中檢查並創建KUBE-SERVICES和KUBE-NODEPORTS兩個鏈,然後在filter表中插入一條iptables規則,將OUTPUT鏈的數據包導入KUBE-SERVICES鏈,另外在nat表中插入兩條iptables規則,將OUTPUT鏈和PREROUTING鏈的數據包導入KUBE-SERVICES鏈;接著在NAT表中創建KUBE-POSTROUTING鏈,然後再NAT表中插入一條iptables規則,將POSTROUTING鏈的數據包導入KUBE-POSTROUTING鏈。
在iptables表中,通過iptables-save可以看到在nat表中創建好的規則,下面是這些規則的示例:
技術分享

syncProxyRules函數在創建完上面iptables自定義鏈和規則後,調用操作系統命令iptables-save –t filter和iptables-save –t nat將filter表和nat表中內容保存到程序緩存中,在程序緩存中添加KUBE-MARK-MASQ鏈。
對於KUBE-MARK-MASQ鏈中所有規則設置了kubernetes獨有MARK標記,在KUBE-POSTROUTING鏈中對NODE節點上匹配kubernetes獨有MARK標記的數據包,進行SNAT處理。
在iptables表中,通過iptables-save可以看到在nat表中創建好的規則,下面是規則示例:
技術分享

Kube-proxy接著對每個服務創建“KUBE-SVC-”鏈,並在nat表中將KUBE-SERVICES鏈中每個目標地址是service的數據包導入這個“KUBE-SVC-”鏈;如果service使用到了NODE節點端口,那麽將KUBE-NODEPORTS鏈中每個目的地址是NODE節點端口的數據包導入這個“KUBE-SVC-”鏈;如果service沒有配置endpoint,那麽REJECT所有數據包,這意味著沒有endpoint的service是無法被訪問到的。如果service已經配置了endpoint,那麽對每個endpoint創建“KUBE-SEP-”開頭的鏈,並在“KUBE-SVC-”鏈中創建iptables規則,將所有“KUBE-SVC-”鏈中的數據包都導入“KUBE-SEP-”開頭的鏈中,接著在每個“KUBE-SEP-”鏈中創建iptables規則,其中一條規則就是對所有由endpoint發出的數據包都導入KUBE-MARK-MASQ鏈中,如果一個service有多個endpoint,那麽就采用隨機方法將數據包導入不同的“KUBE-SEP-”開頭的鏈中,其實如果一個service對應多個endpoint(相當於一個service對應多個POD),其實就意味著要實現負載均衡,默認情況下是采用隨機的方法從“KUBE-SVC-”鏈向“KUBE-SEP-”鏈轉發數據包,但是如果service的sessionAffinity配置成了ClientIP,那麽在一定時間範圍內向“KUBE-SVC-”鏈請求的數據包都會發給固定的“KUBE-SEP-”鏈,通過這種方式實現業務應用的會話保持。
接著刪除程序緩存中已經不存在的“KUBE-SVC-”鏈和“KUBE-SEP-”鏈,最後添加一條iptables規則目的地址是本地的數據包導入KUBE-NODEPORTS鏈中。
在iptables表中,通過iptables-save可以看到在nat表中創建好的“KUBE-SVC-”鏈和“KUBE-SEP-”鏈,以及這些鏈中的規則,下面是這些規則示例:
技術分享
如果一個service後端有多個POD,那麽在iptables表中通過iptables-save可以看到,下面是使用負載均衡後的規則示例:
技術分享
通過上面規則示例可以看到service如何向後端POD負載均衡分發數據包。
在負載均衡實際使用中,最常用的還有會話保持功能,也就是說一個客戶端同服務器端建立會話連接之後,要保證這個會話連接,通過iptables來實現就需要使用recent模塊,kube-proxy會使用“-m recent –rcheck –seconds 180 –reap”命令來實現會話保持,目前還無法配置會話保持的持續時間,因為kube-proxy在代碼中寫成了180秒,期待以後可以作為參數傳入。
Kube-proxy將程序緩存中的iptables規則通過iptables-restore命令更新到NODE節點操作系統中。
Kube-proxy配置後的Iptables數據包流入圖如下:
技術分享
從這張圖上可以看到,從主機網卡上得到的數據包在經過PREROUTING鏈的nat表時,被導入kube-proxy的KUBE-SERVICES鏈,然後被導入KUBE-SVC-XXX鏈,這裏的XXX表示十六位字符,是由SHA256 算法生成哈希值後通過base32進行編碼,然後取16位,最後數據包被導入KUBE-SEP-XXX,數據包被DDAT到一個POD上,然後返回到PREROUTING鏈中,如果不需要路由,那麽發送給本地上層協議棧,否則路由出主機網卡。
下面是kubernetes環境下NODE節點、service、POD和Docker容器的示意圖,用於形象的展現這四者之間的關系。
技術分享
在這個kubernetes環境下有兩個NODE節點,IP分別是192.168.1.100和192.168.1.101,有兩個ClusterIP模式的service,IP分別是172.16.100.238和172.19.216.162,每個service對應一個POD,在每個POD中。
從上圖中可以看到在每個NODE節點上都會存在service,service在物理上是不存在的,只是在iptables中,POD在物理上也是不存在的,只是一個概念,這個概念是由POD中POD容器來實現的,POD容器是物理存在的。在ClusterIP模式下,POD容器采用HOST模式創建,用戶容器采用Container模式創建,也就是說用戶容器同POD容器共享網絡命名空間、IPC命名空間和文件系統命名空間,通過引入POD容器來實現邏輯上POD概念。
在名稱是nginx的POD上,用戶容器如果要訪問名稱是nginx2的service,經過NODE節點192.168.1.100上的iptables表路由到了NODE節點192.168.1.101上,在NODE節點192.168.1.101上通過iptables裏面kube-proxy創建的規則就會目標重定向給名稱是nginx2的POD,最後這個POD上面的用戶容器收到訪問請求。
下面是使用NodePort模式的service示意圖:
技術分享
如果service使用ClusterIP模式,由於service是個虛擬的概念,所以service對應的IP其實也是個虛擬IP,在真是的外部物理網絡中是無法訪問的,所以只能在kubernetes集群中使用,在這張圖上service使用了NodePost模式,從圖中就可以清楚的看到kube-proxy在NODE節點上創建端口,kubernetes默認在30000-32767之間選擇端口號給service,並且建立從NODE節點上物理端口到service的iptables規則,這樣kubernetes外部應用就可以通過訪問NODE節點IP和端口來實現訪問service的目的。

Kubernetes1.2如何使用iptables