天天看點

kubernetes之kube-proxy

作者:甯靜知行者

kube-proxy

kube-proxy 是kubernetes 的核心元件,部署在每個節點上,是實作Kubernetes Service通信與負載均衡的重要機制,kube-proxy負載為pod建立代理服務,從apiserver擷取所有service資訊,并根據service資訊建立代理服務,實作service到 pod的請求路由與轉發,進而實作K8s層級的轉發網絡。

在k8s中,提供相同服務的一組pod抽象成一個service,通過service統一提供對外通路的入口,每個service都有一個VIP和端口。

kube-proxy 存在于每個節點上,主要用于實作service的功能,具體來說,就是實作叢集内的用戶端pod通路service,或是叢集外部通過nodeport等方式通路service。在目前的版本中,kube-proxy 預設通過iptables模式,在各個節點上生成相應的iptables規則 進行實作service的負載,但是随着service數量增大,iptables模式由于線性查找比對、全量更新等特點,其性能會顯著下降,從k8s的1.8版本開始,kube-proxy引入了ipvs模式,ipvs模式與iptables同樣基于netfilter,但是采用hash表,是以當service數量達到一定規模時,hash查表的速度優勢就會顯現出來,進而提高service的性能。

kube-proxy 會定時從 etcd 擷取service的資訊來處理相應的政策,維護網絡規則和四層負載均衡工作,在k8s叢集中,微服務是由kube-proxy來實作負載均衡,在每一個節點上都會存在

來看下 service/endpoints/pod的關系

kubernetes之kube-proxy

Service/Pod/Endpoints關系

kube-proxy 目前實作了三種代理模式: userspace,Iptables,ipvs

userspace 是1.0 以前的預設模式,從1.1 之後增加了iptables,從1.2開始預設為iptables

  • userspace mode: userspace是在使用者空間,通過kube-proxy來實作service的代理服務

    這種模式下,service的請求會先從使用者空間進入核心 iptables,然後再回到使用者空間,由kube-proxy完成後端 endpoints的選擇和代理工作,這樣流量從使用者空間進出核心帶來的性能損耗是不可接受的。kube-proxy會持續監聽service以及endpoints 對應的變化,對每個service,它都為其在本地節點開放一個端口,作為其服務代理端口,發往該端口的請求會采用一定的政策轉發給與該服務對應的後端Pod實體。kube-proxy同時會在本地節點設定iptables規則 ,配置一個VIP,把發往vip的請求重定向到與該vip對應的服務代理端口上

kubernetes之kube-proxy

userspace

  • iptables 模式

    完全利用核心 iptables來實作sevice的代理和負載均衡

    iptables mode因為使用iptable NAT來完成轉發,也存在不可忽視的性能損耗。另外,如果叢集中存在上萬的Service/Endpoint,那麼Node上的iptables rules将會非常龐大,性能也會降低。

    iptables 模式與 userspace 相同,kube-proxy 持續監聽 Service 以及 Endpoints 對象的變化;但它并不在本地節點開啟反向代理服務,而是把反向代理全部交給 iptables 來實作;即 iptables 直接将對 VIP 的請求轉發給後端 Pod,通過 iptables 設定轉發政策

kubernetes之kube-proxy

iptables

基于iptables的分析

來檢視下kube-proxy生成的iptables規則,有綁定本地nodeport的為例 ingress-controller的service(有5個Pod)

iptables -S -t nat | grep PREROUTING           
-A PREROUTING -m comment --comment "kubernetes service portals" -j KUBE-SERVICES # 增加了一條規則,直接跳轉到 KUBE-SERVICES           

再來看下監聽本地的端口的方式

iptables -S -t nat | grep KUBE-SERVICES | grep LOCAL           
-A KUBE-SERVICES -m comment --comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" -m addrtype --dst-type LOCAL -j KUBE-NODEPORTS           

這裡的符合本地網上的流量都跳轉到 KUBE-NODEPORTS 鍊

iptables -S -t nat | grep KUBE-NODEPORTS           
-A KUBE-NODEPORTS -p tcp -m comment --comment "ingress-nginx/ingress-nginx:http" -m tcp --dport 80 -j KUBE-MARK-MASQ # 進行設定辨別,會繼續轉入下一個規則

-A KUBE-NODEPORTS -p tcp -m comment --comment "ingress-nginx/ingress-nginx:http" -m tcp --dport 80 -j KUBE-SVC-REQ4FPVT7WYF4VLA  # 對于本機的80端口會跳轉到KUBE-SVC-REQ4FPVT7WYF4VLA           

再來檢視

iptables -S -t nat | grep KUBE-SVC-REQ4FPVT7WYF4VLA           

顯示

-A KUBE-SVC-REQ4FPVT7WYF4VLA -m statistic --mode random --probability 0.20000000019 -j KUBE-SEP-5GIHTAZH63ZXHYVD
-A KUBE-SVC-REQ4FPVT7WYF4VLA -m statistic --mode random --probability 0.25000000000 -j KUBE-SEP-56E4RGI7RFJDTTUP
-A KUBE-SVC-REQ4FPVT7WYF4VLA -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-NC535QQK4BRABVZE
-A KUBE-SVC-REQ4FPVT7WYF4VLA -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-6HG3EL2ZYY4VVZWG
-A KUBE-SVC-REQ4FPVT7WYF4VLA -j KUBE-SEP-SXD3CSKRRVR34ZQX

# 以上的規則裡有--probability,使流量有機率性的進入某個鍊
# 以上是 20% 機率進入到 KUBE-SEP-5GIHTAZH63ZXHYVD
#       25% 機率進入到 KUBE-SEP-56E4RGI7RFJDTTUP
#       33% 機率進入到 KUBE-SEP-NC535QQK4BRABVZE
#       50% 機率進入到 KUBE-SEP-6HG3EL2ZYY4VVZWG
#			其餘進入   KUBE-SEP-SXD3CSKRRVR34ZQX           
iptables -S -t nat | grep "A KUBE-SEP-5GIHTAZH63ZXHYVD"
-A KUBE-SEP-5GIHTAZH63ZXHYVD -s 10.168.0.44/32 -j KUBE-MARK-MASQ
-A KUBE-SEP-5GIHTAZH63ZXHYVD -p tcp -m tcp -j DNAT --to-destination 10.168.0.44:80 # 進入了DNAT的規則,轉發到某個一個pod上了           

同理可以驗證上面的幾個鍊,也是轉發到具體的pod上

  • ipvs

    在k8s 1.8以上的版本中開始支援ipvs

    ipvs 是基于 NAT實作的

    與iptables ,userspace一樣,kube-proxy 會監聽service與 endpoints的變化,不過它不會建立反向代理,也不會建立大量的iptables規則,而是通過netlink建立ipvs規則,并使用k8s service與endpoints資訊,對所在節點的ipvs規則進行定期同步;netfilter與iptables底層都是基于netfilter鈎子,但是netlink 由于采用了hash table 而且直接工作在核心,在性能上比iptables 更優

kubernetes之kube-proxy

ipvs

繼續閱讀