kube-proxy 分析
kube-proxy 是一層代理,主要用於實現 Service 這個 Object。
Service 有一個 ClusterIP,這是一個虛擬 IP 應對 Service 後面的 pod,pod 的銷燬和建立會有 ip 不固定的問題。除了能夠遮蔽後端的 pod 的 IP 之外,Service 還可以有負載均衡的作用。
Endpoint 維護的是 Service 和 Pod 的對映關係,如果 pods 變動,Endpoint 也會變動。Service 本身指定義了 ClusterIP 和 port 的對映。Endpoints 記錄了 pod 的 ip 和埠。
主要的訪問方式是通過 NAT 實現的,如果使用 iptables 的話,就設定匹配目標埠以後,DNAT 轉發到目的地址。
我看程式碼的時候,發現有個函式叫 birth cry 挺有意思的,表示打程式啟動的一條 log。
Kube-proxy 主要監聽兩個物件,一個是 Service,一個是 Endpoint
這些 Objects 對應的處理函式有不同的實現,現在先看一下 iptables 的實現
當 Service 有更新的時候就會更新對應的 iptables 規則。
func (c *ServiceConfig)Run(stopCh <-chan struct{}) { defer utilruntime.HandleCrash() glog.Info("Starting service config controller") defer glog.Info("Shutting down service config controller") if !controller.WaitForCacheSync("service config", stopCh, c.listerSynced) { return } for i := range c.eventHandlers { glog.V(3).Infof("Calling handler.OnServiceSynced()") c.eventHandlers[i].OnServiceSynced() } <-stopCh }
會呼叫 OnServiceSynced,然後具體呼叫實現者的方法。
Proxier
Netfilter
Netfilter 是核心模組的控制程式碼,ipvs 和 iptables 都是基於 Netfilter 實現的。
iptables
用 iptables 配置 DNAT ,然後再用概率模組做負載均衡。kube-proxy iptables 的實現主要依賴於 filter 和 nat。
# Masquerade -A KUBE-MARK-DROP -j MARK --set-xmark 0x8000/0x8000 -A KUBE-MARK-MASQ -j MARK --set-xmark 0x4000/0x4000 -A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -m mark --mark 0x4000/0x4000 -j MASQUERADE # clusterIP and publicIP -A KUBE-SERVICES ! -s 10.244.0.0/16 -d 10.98.154.163/32 -p tcp -m comment --comment "default/nginx: cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ -A KUBE-SERVICES -d 10.98.154.163/32 -p tcp -m comment --comment "default/nginx: cluster IP" -m tcp --dport 80 -j KUBE-SVC-4N57TFCL4MD7ZTDA -A KUBE-SERVICES -d 12.12.12.12/32 -p tcp -m comment --comment "default/nginx: loadbalancer IP" -m tcp --dport 80 -j KUBE-FW-4N57TFCL4MD7ZTDA # Masq for publicIP -A KUBE-FW-4N57TFCL4MD7ZTDA -m comment --comment "default/nginx: loadbalancer IP" -j KUBE-MARK-MASQ -A KUBE-FW-4N57TFCL4MD7ZTDA -m comment --comment "default/nginx: loadbalancer IP" -j KUBE-SVC-4N57TFCL4MD7ZTDA -A KUBE-FW-4N57TFCL4MD7ZTDA -m comment --comment "default/nginx: loadbalancer IP" -j KUBE-MARK-DROP # Masq for nodePort -A KUBE-NODEPORTS -p tcp -m comment --comment "default/nginx:" -m tcp --dport 30938 -j KUBE-MARK-MASQ -A KUBE-NODEPORTS -p tcp -m comment --comment "default/nginx:" -m tcp --dport 30938 -j KUBE-SVC-4N57TFCL4MD7ZTDA # load balance for each endpoints -A KUBE-SVC-4N57TFCL4MD7ZTDA -m comment --comment "default/nginx:" -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-UXHBWR5XIMVGXW3H -A KUBE-SVC-4N57TFCL4MD7ZTDA -m comment --comment "default/nginx:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-TOYRWPNILILHH3OR -A KUBE-SVC-4N57TFCL4MD7ZTDA -m comment --comment "default/nginx:" -j KUBE-SEP-6QCC2MHJZP35QQAR # endpoint #1 -A KUBE-SEP-6QCC2MHJZP35QQAR -s 10.244.3.4/32 -m comment --comment "default/nginx:" -j KUBE-MARK-MASQ -A KUBE-SEP-6QCC2MHJZP35QQAR -p tcp -m comment --comment "default/nginx:" -m tcp -j DNAT --to-destination 10.244.3.4:80 # endpoint #2 -A KUBE-SEP-TOYRWPNILILHH3OR -s 10.244.2.4/32 -m comment --comment "default/nginx:" -j KUBE-MARK-MASQ -A KUBE-SEP-TOYRWPNILILHH3OR -p tcp -m comment --comment "default/nginx:" -m tcp -j DNAT --to-destination 10.244.2.4:80 # endpoint #3 -A KUBE-SEP-UXHBWR5XIMVGXW3H -s 10.244.1.2/32 -m comment --comment "default/nginx:" -j KUBE-MARK-MASQ -A KUBE-SEP-UXHBWR5XIMVGXW3H -p tcp -m comment --comment "default/nginx:" -m tcp -j DNAT --to-destination 10.244.1.2:80
這是一個例項,首先通過 clusterIP 的 -d 匹配目的地址,還有 dport 匹配目的埠,轉入對應的 SVC 鏈。
SVC 聯通過 -m statistic 模組負載均衡到不同的 Endpoint 鏈上,每個 Endpoint 鏈又有一個 DNAT 到對應的 pod
的 IP:port 上,總的來說就是用 DNAT 實現 clusterIP 的代理,用 statistic 模組實現按概率的負載均衡(按概率進入不同的 Endpoint 鏈當中)。
ipvs
ipvs 有相對更好的效能,更復雜的負載均衡的演算法以及健康狀態檢查等。
可以看到 kube-ipvs0 上的10.102.128.4 對應的 Service 的 ClusterIP,而 RealServer 對映到了不同的 Endpoint 上。
iptables 的匹配是 hash 的,而不同根據一個鏈一個鏈的匹配,效率更高。
# kubectl describe svc nginx-service Name:nginx-service ... Type:ClusterIP IP:10.102.128.4 Port:http3080/TCP Endpoints:10.244.0.235:8080,10.244.1.237:8080 Session Affinity:None # ip addr ... 73: kube-ipvs0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN qlen 1000 link/ether 1a:ce:f5:5f:c1:4d brd ff:ff:ff:ff:ff:ff inet 10.102.128.4/32 scope global kube-ipvs0 valid_lft forever preferred_lft forever # ipvsadm -ln IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:PortForward Weight ActiveConn InActConn TCP10.102.128.4:3080 rr -> 10.244.0.235:8080Masq100 -> 10.244.1.237:8080Masq100