Kube-proxy的功能
我們知道POD的IP是動態分配的而且經常會變,所以為了可以透過一個不太容易變化的IP訪問POD就會使用一個叫做service的東西,透過標籤選擇器和POD進行關聯。
Service提供常用的型別有:
- ClusterIP,也是預設方式。Service會分配一個叢集內部的固定虛擬IP,實現叢集內透過該IP來對POD進行訪問。這個又有兩類,上面說到的最普通的Service,ClusterIP還有一種是Headless Service,這種形式不會分配IP也不會透過kube-proxy做反向代理或者負載均衡,而是透過DNS提供穩定的網路ID來訪問,DNS會將headless service的後端直接解析為POD的IP列表,這種主要是共StatefulSet型別使用。
- NodePort,這種型別的Service是除了使用ClusterIP的功能外還會對映一個宿主機隨機埠到service上,這樣叢集外部可以透過宿主機IP+隨機埠來訪問。
- LoadBalancer:和nodePort類似,不過除了使用ClusterIP和NodePort之外還會向使用的公有云申請一個負載均衡器,從而實現叢集外部透過LB來訪問服務
- ExternalName:是Service的一種特例,此模式主要面對執行在叢集外部的服務,透過它可以將外部服務對映到k8s叢集,具備k8s內服務的一些特性,來為叢集內部提供服務。
我們要說一下ClusterIP這個東西,這是透過yaml安裝的一個coredns外掛,它就的配置清單中就定義了service。
這個servic ip地址段是在部署API SERVER時API SERVER服務啟動配置檔案中定義的地址段。而且在Flannel中都沒有這個地址段。相比之下POD的IP其實是實實在在配置在容器中的,最終要的是叢集中任何節點上都沒有關於這個網段的路由資訊,那麼叢集內部是如何透過這個完全虛擬的IP來訪問的呢?這就要說到kube-proxy了
你看在叢集的任何機器上都可以PING通這個地址。我們來看看這個svc的詳情
這個10.254.0.2 serviceIP關聯了Endpoints(這裡是2個endpoints因為POD開放了TCP和UDP的53號埠,所以是2個)。那麼現在就有了一個大致的認識就是你訪問10.254.0.2就是訪問172.30.23.2,而這個172的IP就是POD的真實IP,這個IP段是在Flannel上配置過的。下面再來看一張圖:
在IPVS規則中定義了訪問10.254.0.2就會轉發到172.30.23.2,而172.30.23.2就是POD的IP。
所以透過上面我們就知道它其實是透過IPVS規則來轉發的根本不是透過路由來實現的。可是你想過沒有這個規則是誰生成的呢?其實就是kube-proxy來生成的,而且這樣的規則會同步到叢集其他機器上,哪怕這個POD沒有執行在自己的機器上也要有這樣的規則,只有這樣才能保證叢集任何一臺主機都可以透過這個serviceIP來訪問到POD,當面臨跨主機的時候才會用到路由規則,由Flannel的隧道來進行轉發到真實POD所在主機,然後由該主機的kube-proxy來轉發到具體的POD上。
這時候我們就明白了kube-proxy的大致作用,當service有了IP、埠以及POD的IP和埠對應關係以及宿主機隨機埠到service的對映,就可以完成對內、外請求的轉發,而轉發就是,本地轉發還是用IPVS規則,而遠端則用了路由資訊。
叢集中每個NODE都執行一個kube-proxy程式,這個就是service的載體。它負責建立和刪除包括更新IPVS規則、通知API SERVER自己的更新,或者從API SERVER哪裡獲取其他kube-proxy的IPVS規則變化來更新自己的。我們說了多次IPVS,其實kube-proxy支援3中模式
Userspace模式
userspace,這種模式時最早的,不過已經不推薦使用了,效率低,因為需要在核心空間和使用者空間轉換。
Iptables模式
這是預設方案,在核心中透過iptables的NAT實現本地轉發和負載均衡。在大規模試用下存在效能問題。
Ipvs模式
可選方案,如果核心支援且使用者指定那麼kube-proxy將使用這種模式。在早期版本的K8S中不支援。
如果POD不在本機怎麼辦
本機是srv01而這個coredns是執行在srv02上,你從srv01訪問會先進行ipvs找到目標POD的IP地址,發現不在本機就透過路由,訪問的網段172.30.23.0走flannel.1這個網路介面,這個介面其實和其他主機的flannel.1透過物理鏈路做了隧道,所以就可以通。那麼10.254.0.2是如何與這個172.30.23.2這個IP建立關係的呢?其實就是service,看下圖