1 緣起
無意中翻閱官方文檔,看到了Kubernetes中的網(wǎng)絡(luò)模型,
于是,開始學(xué)習(xí),分享如下。
官方文檔:
網(wǎng)絡(luò)模型https://kubernetes.io/docs/concepts/services-networking/
Servicehttps://kubernetes.io/docs/concepts/services-networking/service/
2 Kubernetes網(wǎng)絡(luò)模型
集群中的每個(gè)Pod會在集群范圍內(nèi)獲取自己唯一的IP地址。
因此,Pod間不需要?jiǎng)?chuàng)建鏈接,同樣不要處理容器端口與主機(jī)端口的映射關(guān)系。
這樣即構(gòu)建了簡潔且向后兼容的模型。
可以將Pod視為虛擬機(jī)或者物理機(jī),比如在為Pod進(jìn)行端口分配、命名、服務(wù)發(fā)現(xiàn)、負(fù)載均衡、應(yīng)用配置和遷移。
Kubernetes在對網(wǎng)絡(luò)實(shí)現(xiàn)上提出如下基本要求(禁止任何故意進(jìn)行網(wǎng)絡(luò)分段):
- Pod與其他節(jié)點(diǎn)的Pod進(jìn)行通信無需NAT
- Node的代理(如系統(tǒng)進(jìn)程、kublet)可以與該節(jié)點(diǎn)的任何Pod通信
注意
:對于支持Pod運(yùn)行于主機(jī)網(wǎng)絡(luò)的平臺(如Linux),當(dāng)Pod獲取節(jié)點(diǎn)的主機(jī)網(wǎng)絡(luò)時(shí),可以不通過NAT與所有節(jié)點(diǎn)的Pod通信。
該網(wǎng)絡(luò)模型不僅僅減少全局復(fù)雜度,最重要是這種設(shè)計(jì)方式與Kubernetes的期望一樣,即應(yīng)用程序從虛擬機(jī)到容器平滑遷移。如果之前的任務(wù)運(yùn)行于虛擬機(jī)中,那么虛擬機(jī)只要有IP即可與項(xiàng)目中其他虛擬機(jī)同通信。兩者的基本模型是一致的。
Kubernetes的IP地址存在于Pod作用域中,包括IP地址和MAC地址(Pod中的容器共享網(wǎng)絡(luò)命名空間),意味著Pod中的容器可以通過localhost在各自端口上相互通信,并且Pod需要管理端口的使用,這與虛擬機(jī)中的處理是一致的,稱為“IP-per-pod”模型。
將Node端口的請求轉(zhuǎn)發(fā)到Pod(稱為主機(jī)端口),但這是非常常規(guī)的操作,如何實(shí)現(xiàn)轉(zhuǎn)發(fā)仍然是容器運(yùn)行時(shí)的處理的,Pod自身是不關(guān)心主機(jī)端口的。
3 Service
Service是將一系列Pod應(yīng)用暴露為網(wǎng)絡(luò)服務(wù)的一種方法。
Kubernetes中不需要編輯應(yīng)用來使用陌生的服務(wù)發(fā)現(xiàn)機(jī)制,Kubernetes為Pod分配了IP地址、獨(dú)立的DNS名稱,通過IP和DNS名稱實(shí)現(xiàn)Pod的負(fù)載均衡。
3.1 動(dòng)機(jī)
Kubernetes中Pod的創(chuàng)建和銷毀是為了集群的正常的運(yùn)行,Pod是非持久性的資源(可以按需要?jiǎng)?chuàng)建和銷毀),如果使用Deployment運(yùn)行應(yīng)用可以動(dòng)態(tài)地創(chuàng)建或銷毀Pod(即水平擴(kuò)縮容)。
雖然每個(gè)Pod可以獲取各自的IP地址,但是在Deployment中,Pod的IP地址是隨時(shí)間發(fā)生變化的,即時(shí)刻A Pod的IP可能和時(shí)刻B的IP不同。
這會導(dǎo)致的問題:集群中如果后端Pod為前端Pod提供服務(wù),前端如何實(shí)時(shí)跟隨變化的后端IP?
答案:使用Service。
3.2 Service資源
Kubernetes中,Service是一種頂層抽象,定義了進(jìn)入Pod的邏輯和策略(有時(shí),這種模式稱為微服務(wù))。Service通過定義selector定向到Pod群組。
比如,一個(gè)無狀態(tài)的鏡像處理后臺有3個(gè)副本,這些副本是可替代的,前端無需關(guān)心他們使用的是哪個(gè),雖然實(shí)際的后臺Pod可能會發(fā)生變更,但是,前端客戶端無需感知以及實(shí)時(shí)跟蹤這些Pod的變化。
Service的這種設(shè)計(jì)方式實(shí)現(xiàn)不同服務(wù)的Pod解耦,結(jié)構(gòu)如下圖所示。
不同業(yè)務(wù)間的Pod通過Service轉(zhuǎn)發(fā)請求與響應(yīng)。
云原生服務(wù)發(fā)現(xiàn)
如果應(yīng)用中可以使用Kubernetes的API進(jìn)行服務(wù)發(fā)現(xiàn),
那么,通過API即可查詢服務(wù)變更情況。
對于非原生應(yīng)用,Kubernetes在應(yīng)用和后端Pod間提供了配置網(wǎng)絡(luò)端口和負(fù)載均衡的入口。
3.3 定義Service
Kubernetes中的Service是REST對象,類似于Pod,與所有REST對象一樣,可以通過POST請求API來創(chuàng)建實(shí)例,Service對象名稱需是有效的RFC 1035標(biāo)簽名稱。
比如,假定每個(gè)Pod監(jiān)聽TCP端口為9376,包含標(biāo)簽:app=MyApp,
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
上述配置創(chuàng)建的Service對象名稱為my-service,將請求轉(zhuǎn)發(fā)到標(biāo)簽為MyApp、TCP端口為9376的Pod上。
Kubernetes為my-service這個(gè)服務(wù)分配IP地址(有時(shí)稱為clusterIP),供Service代理使用。
控制器為Service選擇器持續(xù)掃描匹配的Pod,然后向my-service提交更新信息。注意
:Service可以將port映射到targetPort,為方便起見,默認(rèn)將port和targetPort設(shè)為相同的值。
Pod中定義端口同時(shí)可以配置名稱,根據(jù)名字可以配置Service中targetPort屬性,如下配置:
在Pod中通過port名稱:http-web-svc,將Servcie中的targetPort綁定到Pod中的containerPort:80。
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app.kubernetes.io/name: proxy
spec:
containers:
- name: nginx
image: nginx:stable
ports:
- containerPort: 80
name: http-web-svc
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app.kubernetes.io/name: proxy
ports:
- name: name-of-service-port
protocol: TCP
port: 80
targetPort: http-web-svc
即使Service中混合多個(gè)Pod使用同一個(gè)配置名稱同樣是可以正常工作的,相同的網(wǎng)絡(luò)協(xié)議使用不同的端口號,這為部署和迭代Service提供了諸多方便。比如更新Pod的可以修改暴露的端口,而無需終止客戶端。默認(rèn)的Service協(xié)議為TCP,也可以使用其他支持的協(xié)議,如:UDP和SCTP。
鑒于Service需要暴露多個(gè)端口,Kubernetes支持在一個(gè)Service對象中定義多個(gè)端口,每個(gè)端口的協(xié)議可以相同,也可以不同。
3.3.1 Service沒有選擇器
Service可以通過選擇器訪問Kubernetes的Pod,當(dāng)使用了沒有選擇器的終端,Service可以抽象出其他類型的后端服務(wù),包括集群外的服務(wù),如:
- 生產(chǎn)環(huán)境使用外部數(shù)據(jù)庫集群,但測試環(huán)境使用自己的數(shù)據(jù)庫;
- 將自己的Service指向有不同Namespace或者其他集群的服務(wù);
- 遷移工作負(fù)載到Kubernetes。
如上情況可以定義沒有Pod選擇器的Servcie,如:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
由于這個(gè)Service沒有選擇器,所以對應(yīng)的終端對象不會自動(dòng)創(chuàng)建??梢允謩?dòng)將Service映射到對應(yīng)的地址和端口,手動(dòng)添加如下:
apiVersion: v1
kind: Endpoints
metadata:
# the name here should match the name of the Service
name: my-service
subsets:
- addresses:
- ip: 192.0.2.42
ports:
- port: 9376
終端對象的名稱必須是有效的DNS子域名。當(dāng)為Service創(chuàng)建終端對象時(shí),對象名稱必須與Service名稱一致,即metadata.name一致。注意
:終端的IP不應(yīng)該是:環(huán)回地址(127.0.0.0/8 for IPv4, ::1/128 for IPv6)或者鏈路本地地址(169.254.0.0/16 and 224.0.0.0/24 for IPv4, fe80::/64 for IPv6)。
終端IP地址不能是其他Kubernetes集群Service的IP,因?yàn)椋琸ube-proxy不支持虛擬IP作為終點(diǎn)。
訪問Service無需區(qū)分有無選擇器。上面的例子中,流量會路由到定義的終端對象:192.0.2.42:9376(TCP協(xié)議)。
Endpoint是Service的映射對象。
注意:Kubernetes API服務(wù)禁止代理沒有映射的Pod。比如執(zhí)行kubectl proxy ,由于這個(gè)限制,該Service沒有選擇器會代理失敗。這會阻止Kubernetes API服務(wù)被用于代理未授權(quán)的終端接入。
ExternalName類型的Service是一類沒有選擇器并且使用DNS名稱的特殊Service。
3.3.2 終端過載
如果終端資源超過1000個(gè),Kubernetes集群(版本v1.22或更高),Endpoints會使用標(biāo)識:endpoints.kubernetes.io/over-capacity: truncated
。該注解說明Endpoints對象過載,控制器會刪除Endpoints,保持1000個(gè)。
3.3.3 Endpoint分片
Endpoint分片是API資源提供可伸縮的Endpoint。雖然概念上與Endpoint非常相似,但是,Endpoint分片允許跨資源分配網(wǎng)絡(luò)。默認(rèn)情況下,Endpoint分片達(dá)到100個(gè)即認(rèn)為是滿載,多余的Endpoint分片會在其他的終端中創(chuàng)建并存儲。
3.3.4 應(yīng)用協(xié)議
appProtoco屬性為每個(gè)Service的端口提供了訪問協(xié)議,該屬性由對應(yīng)的Endpooints和EndpointSlice對象進(jìn)行映射。
該屬性遵循Kubernetes標(biāo)準(zhǔn)標(biāo)簽語法,值應(yīng)為IANA標(biāo)準(zhǔn)服務(wù)名稱或者域名前綴名稱,如mycompany.com/my-custom-protocol。
3.4 虛擬IP和服務(wù)代理
Kubernetes集群的每個(gè)節(jié)點(diǎn)(Node)都會運(yùn)行kube-proxy,kube-proxy是Service虛擬IP的實(shí)現(xiàn)方式(除了ExternalName)。
3.4.1 為什么不使用round-robin域名系統(tǒng)
一個(gè)常見的問題是:為什么Kubernetes依賴于代理將流量轉(zhuǎn)發(fā)給后端。有沒有其他方案呢?
比如,是否可以配置有多個(gè)A值(或IPv6的AAAA) DNS以及依賴round-robin名稱的解析?
Service使用代理的幾點(diǎn)原因:
- DNS的實(shí)現(xiàn)在很長一段時(shí)間中不遵守記錄TTL(存活時(shí)間)并且緩存應(yīng)該過期的查詢結(jié)果;
- 一些應(yīng)用使用DNS搜索一次,會永久緩存該結(jié)果;
- 雖然應(yīng)用和相關(guān)工具庫重新解析,但是,DNS記錄的低存活時(shí)間或者零存活時(shí)間會導(dǎo)致DNS負(fù)載增加,導(dǎo)致DNS最終很難管理。
3.4.2 配置
kube-proxy可以通過配置使用不同的啟動(dòng)模式。
- kube-proxy通過ConfigMap進(jìn)行配置,ConfigMap可以有效清除無需使用的kube-proxy功能;
- CoinfigMap不支持實(shí)時(shí)重載配置;
- kube-proxy的ConfigMap參數(shù)并不是總是有效的,因?yàn)?,有硬件要求。比如,你的操作系統(tǒng)不允許使用iptables命令,kube-proxy內(nèi)核的標(biāo)準(zhǔn)實(shí)現(xiàn)將無法正常工作。
3.4.3 用戶空間代理模式
該模式下,kube-proxy監(jiān)視Kubernetes控制平面中Service和Endpoint對象的添加和移除。
kube-proxy在本地節(jié)點(diǎn)(Node)上為每個(gè)Service開放一個(gè)隨機(jī)選擇的端口。
任何連接到這個(gè)“代理端口”的服務(wù)都會代理到Service的后端Pod上(通過Endpoint)。
kube-proxy Sevice根據(jù)SessionAffinity配置決定使用哪個(gè)后端Pod。
最后,用戶空間代理安裝iptables規(guī)則來獲取流量,
流量分配被到Service的clusterIP(虛擬IP)和端口上。
kube-proxy將流量重定向到后端Pod的代理端口上,
默認(rèn)情況下,kube-proxy在用戶空間模式下通過round-robin算法選后端Pod,
過程如下圖所示,由圖可知,流量分發(fā):traffic->clusterIP->kube-proxy->pod。
圖片地址:https://d33wubrfki0l68.cloudfront.net/e351b830334b8622a700a8da6568cb081c464a9b/13020/images/docs/services-userspace-overview.svg
3.4.4 iptables代理模式
iptable代理模式中,kube-proxy通過Kubernetes控制平面監(jiān)控Service和Endpoint對象的添加和移除。kube-proxy為每個(gè)Servcie安裝iptable規(guī)則,將流量分配到Service的clusterIP和端口上,然后重定向到Service的后端Pod上。kube-proxy為每個(gè)Endpoint對象安裝iptable規(guī)則來選擇后端Pod。默認(rèn)情況下,iptable模式下的kube-proxy是純隨機(jī)選擇后端Pod。
該模式的架構(gòu)示意圖如下圖所示,由圖可知,流量分發(fā):traffic->clusterIP->pod或者traffic->kube-proxy->pod。
原圖地址:https://d33wubrfki0l68.cloudfront.net/27b2978647a8d7bdc2a96b213f0c0d3242ef9ce0/e8c9b/images/docs/services-iptables-overview.svg
使用iptable處理流量系統(tǒng)開銷很小,因?yàn)長inux網(wǎng)絡(luò)篩選器處理流量時(shí)無需進(jìn)行用戶空間和內(nèi)核空間的切換。這種處理方式貌似更加可靠。
如果kube-proxy運(yùn)行在iptable模式化下,選中的第一個(gè)Pod無響應(yīng),連接會失敗。與用戶空間模式不同的是:用戶空間模式下,kube-proxy在第一個(gè)Pod中無法獲取響應(yīng)時(shí),會自動(dòng)向其他Pod發(fā)起重試請求。
可以使用就緒探針(readiness)驗(yàn)證后端Pod是否正常工作,因此iptable模式下kube-proxy只能觀測到測試正常的后端Pod。這樣意味著無需將流量通過kube-proxy分發(fā)到Pod就可以知道響應(yīng)異常。
3.4.5 IPVS代理模式
ipvs模式下,kube-proxy觀測kubernetes的Service和Endpoint,調(diào)用netlink接口創(chuàng)建對應(yīng)的IPVS規(guī)則,并定期向Kubernetes的Sevice和Endpoint同步IPVS規(guī)則。該控制回環(huán)保證IPVS與期望的狀態(tài)是一致的。當(dāng)訪問Servcie時(shí),IPVS將流量直接定向到后端Pod。
IPVS模式是基于網(wǎng)絡(luò)篩選器回調(diào)功能,與iptable模式是非常相似的,不同的是,IPVS使用hashtable作為數(shù)據(jù)結(jié)構(gòu)并在內(nèi)核空間中進(jìn)行工作。這意味著IPVS模式下,kube-proxy流量重定向的時(shí)延比iptable模式中更低,同步代理規(guī)則的性能會更好。與其他模式相比,IPVS也支持更高吞吐量。
該模式的架構(gòu)示意圖如下圖所示,由圖可知,流量分發(fā):traffic->clusterIP->pod或者traffic->kube-proxy->pod。
原圖地址:https://d33wubrfki0l68.cloudfront.net/2d3d2b521cf7f9ff83238218dac1c019c270b1ed/9ac5c/images/docs/services-ipvs-overview.svg
IPVS為后端Pod的流量分發(fā)提供多種均衡策略:
- rr:輪詢
- lc:最小連接(開啟連接數(shù)量最少)
- dh:目標(biāo)地址Hash
- sh:源Hash
- seq:期待延遲最少
- nq:非隊(duì)列
注意:IPVS模式下運(yùn)行kube-proxy,需保證啟動(dòng)kube-proxy前,在節(jié)點(diǎn)(Node)中IPVS是可用的。
kube-proxy以IPVS代理模式啟動(dòng)時(shí),會確認(rèn)IPVS內(nèi)核模塊是否可用,如果沒有檢測到可用的IPVS內(nèi)核模塊,kube-proxy會回退使用iptable代理模式。
這些代理模型,流量會綁定到Service的IP和Port(代理了后端Pod的Service),客戶端無需感知任何關(guān)于Kubernetes、Servcie或者Pod。
如果想將某個(gè)特定的客戶端的流量發(fā)送到同一個(gè)Pod,可以基于客戶端IP地址設(shè)置會話,通過屬性service.spec.sessionAffinity,配置為ClientIP,默認(rèn)為None,同時(shí)支持配置會話最大存活時(shí)間,通過屬性service.spec.sessionAffinityConfig.clientIP.timeoutSeconds配置,默認(rèn)為10800秒,即3小時(shí)。
注意:Windows系統(tǒng)中,Service不支持最大會話存活時(shí)間。
3.5 多個(gè)端口Service
對于某些Service需要暴露多個(gè)端口。Kubernetes允許在Service對象中配置多個(gè)端口。一個(gè)Service配置多個(gè)端口,必須給端口配置名稱,明確目的。多個(gè)端口配置樣例如下:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 9376
- name: https
protocol: TCP
port: 443
targetPort: 9377
注意:與Kubernetes命名一致,端口的名稱只能包含小寫字母和中劃線。端口名稱的開始和結(jié)束必須是字母或數(shù)字。如合法的:123-abc,web;不合法:123_abc,-web。
3.6 選擇IP地址
通過配置.spec.clusterIP屬性,在Service創(chuàng)建請求中指定集群的IP地址。如,想重用已經(jīng)有DNS或者原有系統(tǒng)已配置IP地址并且很難重新配置。
選擇的IP地址須滿足:在API server配置的service-cluster-ip-range CIDR范圍內(nèi),有效的IPv4或者IPv6地址。如果創(chuàng)建的Service包含無效的clusterIP地址,API server會返回422狀態(tài)碼,表明錯(cuò)誤。
3.7 流量策略
3.7.1 外部流量策略
通過屬性spec.externalTrafficPolicy控制流量在外部資源的分發(fā)??捎玫念愋陀蠧luster和Local。Cluster:流量分發(fā)到已就緒的Endpoint,Local:只分發(fā)到已就緒的本地節(jié)點(diǎn)Endpoint。如果流量策略為Local,但是沒有本地節(jié)點(diǎn)Endpoint,kube-proxy不會將流量轉(zhuǎn)發(fā)到相關(guān)的Service。
注意:如果為kube-proxy開啟ProxyTerminatingEndpoints屬性,kube-proxy會檢測節(jié)點(diǎn)是否有本地Endpoint以及所有本地Endpoint是否標(biāo)記為terminating。如果有本地Endpoint并且所有本地Endpoint標(biāo)記為terminating,kube-proxy會忽略Local策略的外部流量。如果外部流量策略為Cluster,本地節(jié)點(diǎn)Endpoint為terminating,kube-proxy會將流量分發(fā)到其他正常的Endpoint。即使健康檢查節(jié)點(diǎn)啟動(dòng)失敗時(shí),這種轉(zhuǎn)發(fā)方式對于終止的Endpoint,仍允許外部負(fù)載均衡器優(yōu)雅地分離出NodePort Service的連接。否則,流量會在Pod終止期間丟失。
3.7.2 內(nèi)部流量策略
通過屬性spec.internalTrafficPolicy控制流量在內(nèi)部資源的分發(fā)。與externalTrafficPolicy一樣,有兩種值:Cluster和Local。Cluster:內(nèi)部流量只分配到就緒的Endpoint;Local:流量值分發(fā)到本地節(jié)點(diǎn)的Endpoint。如果流量策略為Local,如果沒有本地Endpoint,kube-proxy會丟棄該流量。
3.8 Service部署
https://blog.csdn.net/Xin_101/article/details/124519232文章來源:http://www.zghlxwxcb.cn/news/detail-467788.html
4 小結(jié)
核心:
(1)集群中的每個(gè)Pod會在集群范圍內(nèi)獲取自己唯一的IP地址,Pod間通信無需建立連接,無需考慮端口映射;
(2)Service是將一系列Pod應(yīng)用暴露為網(wǎng)絡(luò)服務(wù)的一種方法,即通過Service訪問Pod;
(3)代理模式有3種:用戶空間代理模式、iptables代理模式和IPVs代理模式;
(4)Kubernetes允許在Service對象中配置多個(gè)端口;
(5)流量分配策略:Cluster和Local兩種方式,Cluster:流量分發(fā)到就緒的Endpoint;Local流量只分發(fā)到本機(jī)Endpoint,Endpoint終止后,則會丟棄流量。文章來源地址http://www.zghlxwxcb.cn/news/detail-467788.html
到了這里,關(guān)于詳解K8S網(wǎng)絡(luò)模型(包含Service講解)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!