在Kubernetes中,Service是用于將運行在一組Pod上的應用程序公開為網絡服務的抽象概念。Service不但為這組Pod提供統(tǒng)一的DNS名稱,還讓Pod之間實現了負載均衡。本文介紹Kubernetes Service的原理、注意事項,以及Service類型選型建議。
基本概念
當Pod創(chuàng)建完成后,如果直接訪問Pod會存在如下問題:
Pod可能會被控制器如Deployment隨時刪除并重建,其訪問結果不具有確定性。
Pod的IP地址是在啟動后動態(tài)分配的,在啟動前無法預知。
應用常常是由多個運行相同程序鏡像的Pod組成,單獨訪問每個Pod并不現實。
為了解決這些問題,Kubernetes提供了Service對象,為Pod提供一個穩(wěn)定的網絡接口和持久的IP地址。Service通過標簽選擇器識別一組目標Pod,使用負載均衡機制在所有Pod之間均衡分配流量,有效地解決了直接訪問Pod存在的問題,保障了應用的高可用和運行效率。
在Kubernetes中,Endpoint是Service用于服務發(fā)現的關鍵資源,用于實時跟蹤與Service選擇器相匹配的Pod的變化。當Pod被刪除或重建導致IP地址變化時,Endpoint會實時更新存儲的Pod IP地址和端口信息,確保Service將流量定向到最新的Pod。
IPVS是一個基于Linux Kernel LVS功能的負載均衡器,通過創(chuàng)建虛擬IP來處理Service的流量,并將其分配到后端的Pod。
在Kubernetes中,創(chuàng)建一個Service時,kube-proxy會在IPVS表中設置規(guī)則。這些規(guī)則定義了如何從Kubernetes節(jié)點的虛擬IP轉發(fā)到后端Pod。您可以通過ipvsadm
命令在集群節(jié)點上查看當前的IPVS路由表和規(guī)則。
iptables通過一組可配置的表和鏈來工作,每條鏈對應一組規(guī)則,用于控制數據包的流向。
在Kubernetes中,創(chuàng)建一個Service時,kube-proxy會在iptables中添加相應的規(guī)則,這些規(guī)則基于Service的標簽選擇器來轉發(fā)數據包到正確的Pod。您可以通過iptables -t nat -L
命令在集群節(jié)點上查看當前的iptables轉發(fā)表和規(guī)則。
Service類型
名稱 | 描述 | 適用場景 | 計費說明 |
默認的服務類型。ClusterIP分配給服務的是一個只能在集群內部訪問的虛擬IP。 | 只需要在集群內部進行服務間的通信,不需要將服務暴露給集群外部。 例如,集群中部署的前端應用Pod需要訪問同一集群中部署的后端數據庫,后端數據庫可以作為ClusterIP運行。 | 不計費。 | |
NodePort會在集群中的節(jié)點上開放端口,從而允許從集群外部通過 | 需要臨時或低流量的應用時,需要從外網暴露一個端口。 例如,在測試環(huán)境中,當您部署調試一個Web應用服務時,可以使用NodePort運行。相較于LoadBalancer模式,不提供跨節(jié)點負載均衡能力,流量只會發(fā)送到一個節(jié)點并很容易達到資源瓶頸。 | 不計費。若需要實現公網訪問,需要為節(jié)點綁定EIP。關于EIP的計費說明,請參見計費概述。 | |
LoadBalancer類型基于NodePort增加了一個外部負載均衡器,使外部流量能夠平滑地分發(fā)到集群中的多個Pod上。Service會自動提供一個外部IP,客戶端可通過此IP訪問服務。該服務既支持在OSI模型的第四層(傳輸層)處理TCP/UDP類型的流量,也可以擴展至第七層(應用層),進行HTTP/HTTPS流量管理。 | 在公共云上運行應用且需要提供一個穩(wěn)定的、易于管理的對外入口。 例如,生產環(huán)境中需要從互聯(lián)網訪問的公共服務,需要承受大量的外部流量并保證高可用性,例如Web應用、API服務等。 | 負載均衡實例將產生費用請參見 | |
ExternalName | ExternalName類型的Service會在集群中將一個內部服務名稱映射到一個外部域名。這種映射使得集群內的Pod可以通過Service Name來訪問外部域名。 | 集群需要訪問暴露在公共域名下的服務。 例如,當您的應用Pod需要訪問外部的數據庫域名時,可以使用ExternalName將域名映射到集群內部的Service Name上,使得集群內部可以直接通過Service Name進行訪問。 | 不計費。 |
Headless Service | Headless Service指沒有虛擬IP的服務。訪問后端Pod時,服務的DNS查詢會直接返回Pod的IP地址列表,而不是單一的服務IP。Headless Service可以直接發(fā)現并連接到特定的Pod。 | 應用需要直接與后端的具體Pod進行通信(而不是通過一個代理或負載均衡器)。 例如,當您部署了有狀態(tài)應用ClickHouse數據庫服務,可以使用Headless Service,使得應用Pod可以直接訪問每個ClickHouse Pod,并且均衡地讀取數據或針對性地寫入數據,提升數據處理的效率。 | 不計費。 |
Service原理
ClusterIP
創(chuàng)建與分配
當您在ACK集群中創(chuàng)建一個ClusterIP類型的Service時,集群控制面會從預定義的Service網段為該Service分配一個虛擬IP地址,這個地址被稱為ClusterIP。ClusterIP只能在集群內訪問,與后端Pod的IP地址網段是隔離的。
流量轉發(fā)
在集群內訪問ClusterIP時,該流量會被kube-proxy捕獲。kube-proxy使用iptables(或者使用IPVS)規(guī)則,使用輪詢調度的方式將流量轉發(fā)到Service后端的一個Pod中。
服務發(fā)現
創(chuàng)建ClusterIP時,CoreDNS服務中會注冊一個對應的DNS記錄。該DNS記錄允許在集群內部通過服務的名字來解析和訪問服務,格式為
服務名.命名空間.svc.cluster.local:端口
,例如nginx.default.svc.cluster.local:80
Pod標簽和端點跟蹤
每個Service都由一組標簽選擇器(Label Selector)定義,決定哪些Pod屬于該Service的后端。
集群控制面會實時監(jiān)控Pod的變動。當匹配Service標簽選擇器的Pod發(fā)生添加、更新或刪除等操作時,控制面將更新Endpoint。
NodePort
創(chuàng)建與分配
當創(chuàng)建NodePort類型的Service時,除了生成一個ClusterIP來允許內部通信之外,集群還會為此Service在節(jié)點上開放一個端口,稱為NodePort。此端口是在指定的端口范圍(默認是30000-32767)中自動選擇的。您也可以手動指定特定的端口。
流量轉發(fā)
kube-proxy組件負責在每個節(jié)點上監(jiān)聽NodePort端口。當一個外部請求到達任意節(jié)點的NodePort時,kube-proxy負責將這個流量路由到對應的ClusterIP上,然后通過ClusterIP進一步路由到后端Pod中。
外部訪問
通過節(jié)點的IP地址加上靜態(tài)端口(NodePort)來訪問,格式為
<NodeIP>:<NodePort>
,作為外部的訪問地址。
LoadBalancer
創(chuàng)建與分配
當創(chuàng)建一個
LoadBalancer
類型的Service且未指定具體的負載均衡器時,集群控制面會自動與負載均衡服務進行交互,新建負載均衡器實例用于處理該Service的流量。更多信息,請參見通過使用已有負載均衡的服務暴露應用和通過使用自動創(chuàng)建負載均衡的服務公開應用。流量轉發(fā)
當外部流量到達負載均衡實例的外部IP時,負載均衡實例會根據負載均衡策略將流量路由到節(jié)點上的端口,每個節(jié)點上的kube-proxy組件接收到流量后,基于iptables或IPVS規(guī)則將流量重定向到后端Pod。
配置路由和健康檢查
負載均衡器自動配置監(jiān)聽Service YAML聲明的端口,并將流量轉發(fā)到集群中符合選擇器條件的Pod上。同時,負載均衡器會配置健康檢查機制,以確保流量只路由到健康的Pod。
外部流量策略Local和Cluster介紹
在集群中,當服務類型為LoadBalancer或NodePort時,您才可以設置外部流量策略externalTrafficPolicy
,來控制從外部網絡到服務的流量路由。此策略有兩種模式:Local和Cluster。不同網絡插件的外部流量策略功能不同。以下介紹Terway-Eniip和Flannel網絡插件的外部流量策略功能對比。
登錄容器服務管理控制臺,在集群列表頁面單擊目標集群的名稱,在基本信息頁簽下集群信息區(qū)域可以查看集群的網絡模式。
Flannel網絡插件
Flannel網絡插件下,流量經由節(jié)點的NodePort轉發(fā)到Pod中。
Local:流量只轉發(fā)給本機的Pod,即流量僅在同一個節(jié)點的Pod中進行轉發(fā)。
Cluster: 流量可以轉發(fā)到集群中其他節(jié)點上的Pod。
Local和Cluster兩種外部流量策略詳細的區(qū)別如下所示。
類別 | Local | Cluster |
負載均衡后端掛載行為 | 僅Pod所在的節(jié)點會掛載到負載均衡后端。 | 所有集群內的節(jié)點都將掛載到負載均衡的后端。 |
負載均衡配額 | 負載均衡配額消耗較少。關于負載均衡配額的詳細介紹,請參見配額限制。 | 集群內所有節(jié)點都掛載到負載均衡后端,會大量消耗負載均衡配額。關于負載均衡配額的詳細介紹,請參見配額限制。 |
訪問負載均衡地址 | 僅Pod所在節(jié)點可以訪問負載均衡地址。 | 集群內任意節(jié)點均可訪問負載均衡地址。 |
Pod負載均衡 | 默認Pod之間負載不均衡。 如果您想要實現Pod之間負載均衡,需要指定策略為wrr,即為Service添加Annotation | 默認Pod之間負載均衡。 |
保留來源IP | 支持。 | 不支持。 |
會話保持 | 支持。 | 不支持。 |
適用場景 | 對需要保留客戶端原始IP地址的應用程序,例如基于原始IP地址的日志記錄。 | 當需要保證服務的高可用性,并且對源IP保存不敏感時,例如大型Web應用集群。 |
Terway-Eniip網絡插件
Terway-Eniip網絡插件下,無論是Local還是Cluster,流量直接轉發(fā)到Pod中。
Local和Cluster兩種外部流量策略詳細的區(qū)別如下表所示。
比較項 | Local | Cluster |
負載均衡后端掛載行為 | Pod直接掛載到負載均衡后端。 | |
負載均衡配額 | 僅掛載業(yè)務Pod,負載均衡配額消耗較少。關于負載均衡配額的詳細介紹,請參見配額限制。 | |
訪問負載均衡地址 | 僅Pod所在節(jié)點可以訪問負載均衡地址。 | 集群內任意節(jié)點均可訪問負載均衡地址。 |
Pod負載均衡 | 默認Pod之間負載均衡。 | |
保留來源IP | 支持。 | |
會話保持 | 支持。 |
注意事項
在使用Service的負載均衡功能之前,建議您了解相關注意事項。詳細信息,請參見Service的負載均衡配置注意事項。