Kubernetes1.2如何使用iptables

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

本次分析的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的目的。算法

相關文章
相關標籤/搜索