k8s iptables

返回主頁

理解kubernetes環境的iptables

node節點的iptables是由kube-proxy生成的,具體實現可以參見kube-proxy的代碼

kube-proxy只修改了filter和nat表,它對iptables的鏈進行了擴充,自定義了KUBE-SERVICES,KUBE-NODEPORTS,KUBE-POSTROUTING,KUBE-MARK-MASQ和KUBE-MARK-DROP五個鏈,並主要通過爲 KUBE-SERVICES鏈(附着在PREROUTING和OUTPUT)增加rule來配製traffic routing 規則,官方定義如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// the services chain
kubeServicesChain utiliptables.Chain = "KUBE-SERVICES"
 
// the external services chain
kubeExternalServicesChain utiliptables.Chain = "KUBE-EXTERNAL-SERVICES"
 
// the nodeports chain
kubeNodePortsChain utiliptables.Chain = "KUBE-NODEPORTS"
 
// the kubernetes postrouting chain
kubePostroutingChain utiliptables.Chain = "KUBE-POSTROUTING"
 
// the mark-for-masquerade chain
KubeMarkMasqChain utiliptables.Chain = "KUBE-MARK-MASQ"    /*對於未能匹配到跳轉規則的traffic set mark 0x8000,有此標記的數據包會在filter表drop掉*/
 
// the mark-for-drop chain
KubeMarkDropChain utiliptables.Chain = "KUBE-MARK-DROP"    /*對於符合條件的包 set mark 0x4000, 有此標記的數據包會在KUBE-POSTROUTING chain中統一做MASQUERADE*/
 
// the kubernetes forward chain
kubeForwardChain utiliptables.Chain = "KUBE-FORWARD"

KUBE-MARK-MASQ和KUBE-MARK-DROP
 這兩個規則主要用來對經過的報文打標籤,打上標籤的報文可能會做相應處理,打標籤處理如下:
(注:iptables set mark的用法可以參見
https://unix.stackexchange.com/questions/282993/how-to-add-marks-together-in-iptables-targets-mark-and-connmark
http://ipset.netfilter.org/iptables-extensions.man.html)
1
2
-A KUBE-MARK-DROP -j MARK --set-xmark 0x8000/0x8000
-A KUBE-MARK-MASQ -j MARK --set-xmark 0x4000/0x4000

  KUBE-MARK-DROP和KUBE-MARK-MASQ本質上就是使用了iptables的MARK命令

1
2
3
4
5
6
Chain KUBE-MARK-DROP (6 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 MARK       all  --  *      *       0.0.0.0/0            0.0.0.0/0            MARK or 0x8000
Chain KUBE-MARK-MASQ (89 references)
 pkts bytes target     prot opt in     out     source               destination
   88  5280 MARK       all  --  *      *       0.0.0.0/0            0.0.0.0/0            MARK or 0x4000

對於KUBE-MARK-MASQ鏈中所有規則設置了kubernetes獨有MARK標記,在KUBE-POSTROUTING鏈中對NODE節點上匹配kubernetes獨有MARK標記的數據包,當報文離開node節點時進行SNAT,MASQUERADE源IP

1
-A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -m mark --mark 0x4000/0x4000 -j MASQUERADE

而對於KUBE-MARK-DROP設置標記的報文則會在KUBE_FIREWALL中全部丟棄  

1
-A KUBE-FIREWALL -m comment --comment "kubernetes firewall for dropping marked packets" -m mark --mark 0x8000/0x8000 -j DROP

 

KUBE_SVC和KUBE-SEP

Kube-proxy接着對每個服務創建“KUBE-SVC-”鏈,並在nat表中將KUBE-SERVICES鏈中每個目標地址是service的數據包導入這個“KUBE-SVC-”鏈,如果endpoint尚未創建,KUBE-SVC-鏈中沒有規則,任何incomming packets在規則匹配失敗後會被KUBE-MARK-DROP。在iptables的filter中有如下處理,如果KUBE-SVC處理失敗會通過KUBE_FIREWALL丟棄

1
2
3
4
Chain INPUT (policy ACCEPT 209 packets, 378K bytes)
 pkts bytes target     prot opt in     out     source               destination        
 540K 1370M KUBE-SERVICES  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
 540K 1370M KUBE-FIREWALL  all  --  *      *       0.0.0.0/0            0.0.0.0/0

 KUBE_FIREWALL內容如下,就是直接丟棄所有報文:

1
2
3
Chain KUBE-FIREWALL (2 references)
 pkts bytes target     prot opt in     out     source               destination        
    0     0 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes firewall for dropping marked packets */ mark match 0x8000/0x8000

下面是對nexus的service的處理,可以看到該規對目的IP爲172.21.12.49(Cluster IP)且目的端口爲8080的報文作了特殊處理:KUBE-SVC-HVYO5BWEF5HC7MD7

1
-A KUBE-SERVICES -d 172.21.12.49/32 -p tcp -m comment --comment "default/sonatype-nexus: cluster IP" -m tcp --dport 8080 -j KUBE-SVC-HVYO5BWEF5HC7MD7

  KUBE-SEP表示的是KUBE-SVC對應的endpoint,當接收到的 serviceInfo中包含endpoint信息時,爲endpoint創建跳轉規則,如上述的KUBE-SVC-HVYO5BWEF5HC7MD7有endpoint,其iptables規則如下:

1
-A KUBE-SVC-HVYO5BWEF5HC7MD7 -m comment --comment "oqton-backoffice/sonatype-nexus:" -j KUBE-SEP-ESZGVIJJ5GN2KKU

KUBE-SEP-ESZGVIJJ5GN2KKU中的處理爲將經過該鏈的所有tcp報文,DNAT爲container 內部暴露的訪問方式172.20.5.141:8080。結合對KUBE-SVC的處理可可知,這種訪問方式就是cluster IP的訪問方式,即將目的IP是cluster IP且目的端口是service暴露的端口的報文DNAT爲目的IP是container且目的端口是container暴露的端口的報文,

1
-A KUBE-SEP-ESZGVIJJ5GN2KKUR -p tcp -m comment --comment "oqton-backoffice/sonatype-nexus:" -m tcp -j DNAT --to-destination 172.20.5.141:8080  

如果service類型爲nodePort,(從LB轉發至node的數據包均屬此類)那麼將KUBE-NODEPORTS鏈中每個目的地址是NODE節點端口的數據包導入這個“KUBE-SVC-”鏈;KUBE-NODEPORTS必須位於KUBE-SERVICE鏈的最後一個,可以看到iptables在處理報文時會優先處理目的IP爲cluster IP的報文,匹配失敗之後再去使用NodePort方式。如下規則表明,NodePort方式下會將目的ip爲node節點且端口爲node節點暴露的端口的報文進行KUBE-SVC-HVYO5BWEF5HC7MD7處理,KUBE-SVC-HVYO5BWEF5HC7MD7中會對報文進行DNAT轉換。因此Custer IP和NodePort方式的唯一不同點就是KUBE-SERVICE中是根據cluster IP還是根據node port進行匹配

1
2
-A KUBE-NODEPORTS -p tcp -m comment --comment "oqton-backoffice/sonatype-nexus:" -m tcp --dport 32257 -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp -m comment --comment "oqton-backoffice/sonatype-nexus:" -m tcp --dport 32257 -j KUBE-SVC-HVYO5BWEF5HC7MD7

如果服務用到了loadblance,此時報文是從LB inbound的,報文的outbound處理則是通過KUBE-FW實現outbound報文的負載均衡。如下對目的IP是50.1.1.1(LB公網IP)且目的端口是443(一般是https)的報文作了KUBE-FW-J4ENLV444DNEMLR3處理。(參考kubernetes ingress到pod的數據流

1
-A KUBE-SERVICES -d 50.1.1.1/32 -p tcp -m comment --comment "kube-system/nginx-ingress-lb:https loadbalancer IP" -m tcp --dport 443 -j KUBE-FW-J4ENLV444DNEMLR3

  如下在KUBE-FW-J4ENLV444DNEMLR3中顯示的是LB的3個endpoint(該endpoint可能是service),使用比率對報文進行了負載均衡控制

1
2
3
4
Chain KUBE-SVC-J4ENLV444DNEMLR3 (3 references)
    10   600 KUBE-SEP-ZVUNFBS77WHMPNFT  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kube-system/nginx-ingress-lb:https */ statistic mode random probability 0.33332999982
    18  1080 KUBE-SEP-Y47C2UBHCAA5SP4C  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kube-system/nginx-ingress-lb:https */ statistic mode random probability 0.50000000000
    16   960 KUBE-SEP-QGNNICTBV4CXTTZM  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kube-system/nginx-ingress-lb:https */

  而上述3條鏈對應的處理如下,可以看到上述的每條鏈都作了DNAT,將目的IP由LB公網IP轉換爲LB的container IP

1
2
3
4
5
6
-A KUBE-SEP-ZVUNFBS77WHMPNFT -s 172.20.1.231/32 -m comment --comment "kube-system/nginx-ingress-lb:https" -j KUBE-MARK-MASQ
-A KUBE-SEP-ZVUNFBS77WHMPNFT -p tcp -m comment --comment "kube-system/nginx-ingress-lb:https" -m tcp -j DNAT --to-destination 172.20.1.231:443
-A KUBE-SEP-Y47C2UBHCAA5SP4C -s 172.20.2.191/32 -m comment --comment "kube-system/nginx-ingress-lb:https" -j KUBE-MARK-MASQ
-A KUBE-SEP-Y47C2UBHCAA5SP4C -p tcp -m comment --comment "kube-system/nginx-ingress-lb:https" -m tcp -j DNAT --to-destination 172.20.2.191:443
-A KUBE-SEP-QGNNICTBV4CXTTZM -s 172.20.2.3/32 -m comment --comment "kube-system/nginx-ingress-lb:https" -j KUBE-MARK-MASQ
-A KUBE-SEP-QGNNICTBV4CXTTZM -p tcp -m comment --comment "kube-system/nginx-ingress-lb:https" -m tcp -j DNAT --to-destination 172.20.2.3:443

從上面可以看出,node節點上的iptables中有到達所有service的規則,service 的cluster IP並不是一個實際的IP,它的存在只是爲了找出實際的endpoint地址,對達到cluster IP的報文都要進行DNAT爲Pod IP(+port),不同node上的報文實際上是通過POD IP傳輸的,cluster IP只是本node節點的一個概念,用於查找並DNAT,即目的地址爲clutter IP的報文只是本node發送的,其他節點不會發送(也沒有路由支持),即默認下cluster ip僅支持本node節點的service訪問,如果需要跨node節點訪問,可以使用插件實現,如flannel,它將pod  ip進行了封裝

  • 至此已經講完了kubernetes的容器中iptables的基本訪問方式,在分析一個應用的iptables規則時,可以從KUBE-SERVICE入手,並結合該應用關聯的服務(如ingress LB等)進行分析。

  • 查看iptables表現最好結合iptables-save以及如iptables -t nat -nvL的方式,前者給出了iptables的具體內容,但比較雜亂;後者給出了iptables的結構,可以方便地看出表中的內容,但是沒有詳細信息,二者結合起來才能比較好地分析。鏈接狀態可以查看/proc/net/nf_conntrack

 

主要參考:https://blog.csdn.net/ebay/article/details/52798074

kube-proxy的轉發規則查看:http://www.lijiaocn.com/%E9%A1%B9%E7%9B%AE/2017/03/27/Kubernetes-kube-proxy.html



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章