k8s 中的 service 如何找到綁定的 Pod 及實現(xiàn) Pod 負載均衡的方法
k8s 中的 service 如何找到綁定的 Pod 以及如何實現(xiàn) Pod 負載均衡
前言
Service 資源主要用于為 Pod 對象提供一個固定、統(tǒng)一的訪問接口及負載均衡的能力。
service 是一組具有相同 label pod 集合的抽象,集群內(nèi)外的各個服務可以通過 service 進行互相通信。
當創(chuàng)建一個 service 對象時也會對應創(chuàng)建一個 endpoint 對象,endpoint 是用來做容器發(fā)現(xiàn)的,service 只是將多個 pod 進行關(guān)聯(lián),實際的路由轉(zhuǎn)發(fā)都是由 kubernetes 中的 kube-proxy 組件來實現(xiàn),因此,service 必須結(jié)合 kube-proxy 使用,kube-proxy 組件可以運行在 kubernetes 集群中的每一個節(jié)點上也可以只運行在單獨的幾個節(jié)點上,其會根據(jù) service 和 endpoints 的變動來改變節(jié)點上 iptables 或者 ipvs 中保存的路由規(guī)則。
endpoint
endpoint 是 k8s 集群中的一個資源對象,存儲在 etcd 中,用來記錄一個 service 對應的所有 pod 的訪問地址。
service 通過 selector 和 pod 建立關(guān)聯(lián)。k8s 會根據(jù) service 關(guān)聯(lián)到 pod 的 podIP 信息組合成一個 endpoint。
如果 service 沒有 selector 字段,當一個 service 被創(chuàng)建的時候,endpoint controller
不會自動創(chuàng)建 endpoint。
$ kubectl get svc -n study-k8s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE go-web-svc ClusterIP 10.233.55.112 <none> 8000/TCP 9d $ kubectl get endpoints -n study-k8s NAME ENDPOINTS AGE go-web-svc 10.233.111.171:8000,10.233.111.172:8000,10.233.72.153:8000 + 2 more... 9d
栗如
上面的 service go-web-svc
,就有一個對應的 endpoint,ENDPOINTS 里面展示的就是 service 關(guān)聯(lián)的 pod 的 ip 地址和端口。
其中 endpoint controller
負載維護 endpoint 對象,主要的功能有下面幾種
1、負責生成和維護所有endpoint對象的控制器;
2、負責監(jiān)聽 service 和對應 pod 的變化;
3、監(jiān)聽到 service 被刪除,則刪除和該 service 同名的 endpoint 對象;
4、監(jiān)聽到新的 service 被創(chuàng)建,則根據(jù)新建 service 信息獲取相關(guān) pod 列表,然后創(chuàng)建對應 endpoint 對象;
5、監(jiān)聽到 service 被更新,則根據(jù)更新后的 service 信息獲取相關(guān) pod 列表,然后更新對應 endpoint 對象;
6、監(jiān)聽到 pod 事件,則更新對應的 service 的 endpoint 對象,將 podIp 記錄到 endpoint中;
kube-proxy
kube-proxy 是 Kubernetes 的核心組件,部署在每個 Node 節(jié)點上,它是實現(xiàn) Kubernetes Service
的通信與負載均衡機制的重要組件; kube-proxy 負責為 Pod 創(chuàng)建代理服務,從 apiserver 獲取所有 server 信息,并根據(jù) server 信息創(chuàng)建代理服務,實現(xiàn)server到Pod的請求路由和轉(zhuǎn)發(fā),從而實現(xiàn)K8s層級的虛擬轉(zhuǎn)發(fā)網(wǎng)絡。
在 k8s 中提供相同服務的一組 pod 可以抽象成一個 service,通過 service 提供統(tǒng)一的服務對外提供服務,kube-proxy 存在于各個 node 節(jié)點上,負責為 service 提供 cluster 內(nèi)部的服務發(fā)現(xiàn)和負載均衡,負責 Pod 的網(wǎng)絡代理,它會定時從 etcd 中獲取 service 信息來做相應的策略,維護網(wǎng)絡規(guī)則和四層負載均衡工作。k8s 中集群內(nèi)部的負載均衡就是由 kube-proxy 實現(xiàn)的,它是 k8s 中內(nèi)部的負載均衡器,也是一個分布式代理服務器,可以在每個節(jié)點中部署一個,部署的節(jié)點越多,提供負載均衡能力的 Kube-proxy 就越多,高可用節(jié)點就越多。
簡單點講就是 k8s 內(nèi)部的 pod 要訪問 service ,kube-proxy 會將請求轉(zhuǎn)發(fā)到 service 所代表的一個具體 pod,也就是 service 關(guān)聯(lián)的 Pod。
同理對于外部訪問 service 的請求,不論是 Cluster IP+TargetPort
的方式;還是用 Node 節(jié)點 IP+NodePort
的方式,都被 Node 節(jié)點的 Iptables 規(guī)則重定向到 Kube-proxy 監(jiān)聽 Service 服務代理端口。kube-proxy 接收到 Service 的訪問請求后,根據(jù)負載策略,轉(zhuǎn)發(fā)到后端的 Pod。
kube-proxy 的路由轉(zhuǎn)發(fā)規(guī)則是通過其后端的代理模塊實現(xiàn)的,其中 kube-proxy 的代理模塊目前有四種實現(xiàn)方案,userspace、iptables、ipvs、kernelspace 。
userspace 模式
userspace 模式在 k8s v1.2
后就已經(jīng)被淘汰了,userspace 的作用就是在 proxy 的用戶空間監(jiān)聽一個端口,所有的 svc 都轉(zhuǎn)到這個端口,然后 proxy 內(nèi)部應用層對其進行轉(zhuǎn)發(fā)。proxy 會為每一個 svc 隨機監(jiān)聽一個端口,并增加一個 iptables 規(guī)則。
從客戶端到 ClusterIP:Port
的報文都會通過 iptables 規(guī)則被重定向到 Proxy Port
,Kube-Proxy 收到報文后,然后分發(fā)給對應的 Pod。
userspace 模式下,流量的轉(zhuǎn)發(fā)主要是在用戶空間下完成的,上面提到了客戶端的請求需要借助于 iptables 規(guī)則找到對應的 Proxy Port
,因為 iptables 是在內(nèi)核空間,這里就會請求就會有一次從用戶態(tài)到內(nèi)核態(tài)再返回到用戶態(tài)的傳遞過程, 一定程度降低了服務性能。所以就會認為這種方式會有一定的性能損耗。
默認情況下,用戶空間模式下的 kube-proxy 通過輪轉(zhuǎn)算法選擇后端。
iptables
首先來簡單了解下 iptables:
iptables 是 Linux 中最常用的一種防火墻工具,除了防火墻它還可以用作 IP 轉(zhuǎn)發(fā)和簡單的負載均衡功能?;?Linux 中的 netfilter 內(nèi)核模塊實現(xiàn)。 Netfilter 在協(xié)議中添加了一些鉤子,它允許內(nèi)核模塊通過這些鉤子注冊回調(diào)函數(shù),這樣經(jīng)過鉤子的所有數(shù)據(jù)都會被注冊在響應鉤子上的函數(shù)處理,包括修改數(shù)據(jù)包內(nèi)容、給數(shù)據(jù)包打標記或者丟掉數(shù)據(jù)包等。iptables 是運行在用戶態(tài)的一個程序,通過 netlink 和內(nèi)核的 netfilter 框架打交道,具有足夠的靈活性來處理各種常見的數(shù)據(jù)包操作和過濾需求。它允許將靈活的規(guī)則序列附加到內(nèi)核的數(shù)據(jù)包處理管道中的各種鉤子上。
Netfilter 是 Linux 2.4.x
引入的一個子系統(tǒng),它作為一個通用的、抽象的框架,提供一整套的 hook 函數(shù)的管理機制,使得諸如數(shù)據(jù)包過濾、網(wǎng)絡地址轉(zhuǎn)換(NAT)和基于協(xié)議類型的連接跟蹤成為了可能。
在 kubernetes v1.2
之后 iptables 成為默認代理模式,這種模式下,kube-proxy 會監(jiān)視 Kubernetes master
對 Service 對象和 Endpoints 對象的添加和移除。 對每個 Service,它會安裝 iptables 規(guī)則,從而捕獲到達該 Service 的 clusterIP(虛擬 IP)和端口的請求,進而將請求重定向到 Service 的一組 backend 中的某個上面。因為流量轉(zhuǎn)發(fā)都是在內(nèi)核進行的,所以性能更高更加可靠。
可以看到該模式下 iptables 來做用戶態(tài)的入口,kube-proxy 只是持續(xù)監(jiān)聽 Service 以及 Endpoints 對象的變化, iptables 通過設置的轉(zhuǎn)發(fā)策略,直接將對 VIP 的請求轉(zhuǎn)發(fā)給后端 Pod,iptables 使用 DNAT 來完成轉(zhuǎn)發(fā),其采用了隨機數(shù)實現(xiàn)負載均衡。
如果 kube-proxy 在 iptables 模式下運行,并且所選的第一個 Pod 沒有響應,則連接失敗。 這與用戶空間模式不同:在這種情況下,kube-proxy 將檢測到與第一個 Pod 的連接已失敗, 并會自動使用其他后端 Pod 重試。
該模式相比 userspace 模式,克服了請求在用戶態(tài)-內(nèi)核態(tài)反復傳遞的問題,性能上有所提升,但使用 iptables NAT 來完成轉(zhuǎn)發(fā),存在不可忽視的性能損耗,iptables 模式最主要的問題是在 service 數(shù)量大的時候會產(chǎn)生太多的 iptables 規(guī)則,使用非增量式更新會引入一定的時延,大規(guī)模情況下有明顯的性能問題。
ipvs
當集群的規(guī)模比較大時,iptables 規(guī)則刷新就會很慢,難以支撐大規(guī)模的集群。因為 iptables 的底層實現(xiàn)是鏈表,對路由規(guī)則的增刪查改都需要遍歷一次鏈表。
在 kubernetes v1.2
之后 ipvs 成為kube-proxy的默認代理模式。ipvs 正是解決這一問題的,ipvs 是 LVS 的負載均衡模塊,與 iptables 比較像的是,ipvs 的實現(xiàn)雖然也基于 netfilter 的鉤子函數(shù),但是它卻使用哈希表作為底層的數(shù)據(jù)結(jié)構(gòu)并且工作在內(nèi)核態(tài),也就是說 ipvs 在重定向流量和同步代理規(guī)則有著更好的性能,幾乎允許無限的規(guī)模擴張。
ipvs 支持三種負載均衡模式:
1、DR模式(Direct Routing);
2、NAT 模式(Network Address Translation);
3、Tunneling(也稱 ipip 模式)。
三種模式中只有 NAT 支持端口映射,所以 ipvs 使用 NAT 模式。linux 內(nèi)核原生的 ipvs 只支持 DNAT,當在數(shù)據(jù)包過濾,SNAT 和支持 NodePort 類型的服務這幾個場景中ipvs 還是會使用 iptables。
ipvs 也支持更多的負載均衡算法:
rr:round-robin/輪詢;
lc:least connection/最少連接;
dh:destination hashing/目標哈希;
sh:source hashing/源哈希;
sed:shortest expected delay/預計延遲時間最短;
nq:never queue/從不排隊
kernelspace
kernelspace 模式是 windows 上的代理模式,這里不展開討論了
服務發(fā)現(xiàn)
service 的 endpoints 解決了容器發(fā)現(xiàn)問題,但是不提前知道 service 的 Cluster IP
,就無法知道 service 服務了。Kubernetes 支持兩種基本的服務發(fā)現(xiàn)模式 —— 環(huán)境變量和 DNS。
環(huán)境變量
當一個 pod 創(chuàng)建完成之后,kubelet 會在該 pod 中注冊該集群已經(jīng)創(chuàng)建的所有 service 相關(guān)的環(huán)境變量,但是需要注意的是,在 service 創(chuàng)建之前的所有 pod 是不會注冊該環(huán)境變量的,所以在平時使用時,建議通過 DNS 的方式進行 service 之間的服務發(fā)現(xiàn)。
舉個例子,一個名稱為 redis-primary 的 Service 暴露了 TCP 端口 6379, 同時給它分配了 Cluster IP 地址 10.0.0.11,這個 Service 生成了如下環(huán)境變量:
REDIS_PRIMARY_SERVICE_HOST=10.0.0.11 REDIS_PRIMARY_SERVICE_PORT=6379 REDIS_PRIMARY_PORT=tcp://10.0.0.11:6379 REDIS_PRIMARY_PORT_6379_TCP=tcp://10.0.0.11:6379 REDIS_PRIMARY_PORT_6379_TCP_PROTO=tcp REDIS_PRIMARY_PORT_6379_TCP_PORT=6379 REDIS_PRIMARY_PORT_6379_TCP_ADDR=10.0.0.11
DNS
可以在集群中部署 CoreDNS 服務(舊版本的 kubernetes 群使用的是 kubeDNS), 來達到集群內(nèi)部的 pod 通過DNS 的方式進行集群內(nèi)部各個服務之間的通訊。
當前 kubernetes 集群默認使用 CoreDNS 作為默認的 DNS 服務,主要原因是 CoreDNS 是基于 Plugin 的方式進行擴展的,簡單,靈活,并且不完全被Kubernetes所捆綁。
同時 k8s 中也建議使用 DNS 來做服務發(fā)現(xiàn)。
Kubernetes DNS 服務器是唯一的一種能夠訪問 ExternalName 類型的 Service 的方式。
總結(jié)
k8s 中一般使用 Service 為 Pod 對象提供一個固定、統(tǒng)一的訪問接口及負載均衡的能力;
k8s 中的負載均衡主要借助于 endpoint 和 kube-proxy 來實現(xiàn);
endpoint 是 k8s 集群中的一個資源對象,存儲在 etcd 中,用來記錄一個 service 對應的所有 pod 的訪問地址,當一個 service 關(guān)聯(lián)的 pod 被刪除,更新,新增,對應的 endpoint 資源都會更新;
kube-proxy 是 Kubernetes 的核心組件,部署在每個 Node 節(jié)點上,它是實現(xiàn) Kubernetes Service
的通信與負載均衡機制的重要組件; kube-proxy 負責為 Pod 創(chuàng)建代理服務,從 apiserver 獲取所有 server 信息,并根據(jù) server 信息創(chuàng)建代理服務,實現(xiàn)server到Pod的請求路由和轉(zhuǎn)發(fā),從而實現(xiàn)K8s層級的虛擬轉(zhuǎn)發(fā)網(wǎng)絡;
kube-proxy 的路由轉(zhuǎn)發(fā)規(guī)則是通過其后端的代理模塊實現(xiàn)的,其中 kube-proxy 的代理模塊目前有四種實現(xiàn)方案,userspace、iptables、ipvs、kernelspace ;
service 的 endpoints 和 kube-proxy 解決了容器的發(fā)現(xiàn)和負載均衡的問題,但是 service 服務如何被內(nèi)部的服務找到呢,Kubernetes 支持兩種基本的服務發(fā)現(xiàn)模式 —— 環(huán)境變量和 DNS;
其中 k8s 中推薦使用 DNS 來做 service 的服務發(fā)現(xiàn),當前 kubernetes 集群默認使用 CoreDNS 作為默認的 DNS 服務,主要原因是 CoreDNS 是基于 Plugin 的方式進行擴展的,簡單,靈活,并且不完全被Kubernetes所捆綁。
參考
【kubernetes service 原理解析】https://zhuanlan.zhihu.com/p/111244353
【service selector】https://blog.csdn.net/luanpeng825485697/article/details/84296765
【一文看懂 Kube-proxy】https://zhuanlan.zhihu.com/p/337806843
【Kubernetes 【網(wǎng)絡組件】kube-proxy使用詳解】https://blog.csdn.net/xixihahalelehehe/article/details/115370095
【Service】https://jimmysong.io/kubernetes-handbook/concepts/service.html
【Service】https://kubernetes.io/zh-cn/docs/concepts/services-networking/service/
【k8s 中的 service 如何找到綁定的 Pod 以及如何實現(xiàn) Pod 負載均衡】https://boilingfrog.github.io/2022/10/16/k8s中的service如何找到綁定的Pod以及如何實現(xiàn)Pod負載均衡/
到此這篇關(guān)于k8s 中的 service 如何找到綁定的 Pod 以及如何實現(xiàn) Pod 負載均衡的文章就介紹到這了,更多相關(guān)k8s 中的 service 實現(xiàn) Pod 負載均衡內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Kubernetes k8s configmap 容器技術(shù)解析
這篇文章主要為大家介紹了k8s configmap 容器技術(shù)解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-08-08kubernetes?Volume存儲卷configMap學習筆記
這篇文章主要為大家介紹了kubernetes?Volume存儲卷configMap學習筆記,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-05-05Google?Kubernetes?Engine?集群實戰(zhàn)詳解
這篇文章主要為大家介紹了Google?Kubernetes?Engine?集群實戰(zhàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-08-08K8s準入控制Admission?Controller深入介紹
本篇我們將聚焦于?kube-apiserver?請求處理過程中一個很重要的部分?--?準入控制器(Admission?Controller)深入講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪2022-04-04