公眾號「架構成長指南」,專注於生產實踐、雲原生、分散式系統、巨量資料技術分享。
對k8s有點了解技術人員,應該都只知道k8s是有服務註冊發現的,今天就分析下這個原理,看看怎麼實現的。
服務註冊與發現是一種機制,用於在叢集中動態地發現和連線不同的服務,比如我們在開發微服務時,經常使用的Eureka
、Nacos
等
Service B 把自己註冊到 Service Registry 叫做 服務註冊
Service A 從 Service Registry 發現 Service B 的節點資訊叫做 服務發現
在K8s叢集中,Pod和服務的數量和位置都是動態變化的,Pod有可能伸縮、重新部署或遷移,在這樣的環境下,如果寫死的服務地址是不可行的,所以服務註冊與發現使得我們的系統能夠自動感知到這種變化。
服務註冊與發現使得我們的系統可以使用服務名稱來存取其他服務,而不需要關心具體的IP地址和埠號。
通過服務註冊與發現可以實現負載均衡,將請求均勻地分發到多個後端服務範例。
當服務範例發生故障或不可用時,服務註冊與發現可以自動檢測並從服務發現機制中移除不可用的範例。這樣,請求將被自動路由到可用的範例上,提高應用程式的容錯性和可用性。
基於上面的介紹,我們瞭解到K8s中的Pod
的生命週期是短暫的,他們的IP地址會不斷變化,如果讓服務消費方去管理這些Pod IP
在做負載均衡呼叫Pod
,那麼會很複雜,為了對外提供統一的入口來提供服務,所以k8s建立了Service
,不管是內部還是外部統一呼叫 Service,然後再由 Service 轉發到後端Pod
Pod 的地址管理則由Endpoints
管理,根據Service
名稱可以查詢Endpoints
資訊,當通過API建立/修改service物件時,endpoints控制器的監聽到Service
物件,然後根據Service
的設定的選擇器建立一個endpoints物件,此物件將pod的IP、容器埠資訊儲存到etcd中。
他們之間關係如下:
同時Endpoints控制器會監聽與Pod相關的事件,包括上下線事件,一旦Endpoints控制器接收到這些事件,它會相應地更新Endpoints資源,將不可用的Pod從Endpoints列表中移除。
由於Service的 IP有可能會變,如果在程式碼裡面寫死Service IP後期維護起來也是比較麻煩的事情,所以通過在建立一個Service時,CoreDNS會為該Service新增一個域名解析記錄,將Service的名稱解析為相應的Cluster IP地址。這樣其他Pod或服務可以通過使用Service名稱來存取該Service。
kube-proxy
是叢集中每個節點上執行的網路代理,它負責將叢集內部的Service暴露給其他Pod或外部網路。它通過在Node節點上設定網路規則和轉發規則,將Service的請求轉發到正確的目標Pod
同時kube-proxy
實現負載均衡演演算法,將進入Service的請求均勻地分發到後端的Pod範例。這確保了在多個副本的情況下,Service能夠平衡地處理請求,提高可用性和效能。
kube-proxy
通過監聽知道了Service、endpoints物件的建立,然後把Service
的CLUSTER-IP
和埠資訊拿出來,建立iptables NAT規則做轉發或通過ipvs模組建立VS伺服器,這樣經過CLUSTER-IP的流量都被轉發到後端pod。
當Service的目標Pod位於同一節點上時,kube-proxy會將請求直接轉發到該節點上的Pod,而不會跨節點轉發。這種情況下,請求不會被傳送到其他節點上。
然而,如果Service的目標Pod分佈在多個節點上,kube-proxy可以通過負載均衡演演算法將請求轉發到其他節點上的Pod。
下面我們基於兩個組態檔,驗證下上面的結論
nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 4
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: mirrorgooglecontainers/serve_hostname
ports:
- containerPort: 80
serve_hostname是k8s官方提供的debug映象,返回hostname的web server,存取pod時會返回hostname。
nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
ports:
- name: service-port
port: 80
protocol: TCP
targetPort: 9376
selector:
app: nginx
type: ClusterIP
可以看到service 的selector
屬性指定了app: nginx
,這樣就能匹配 deplyment 中定義的 nginx pod
我們依次執行以上兩個檔案,最後獲取到資訊如下
Service地址檢視
kubectl get svc nginx-service
Pod資訊檢視
kubectl get pods -l app=nginx -o wide
Endpoints資訊檢視
根據service名稱查詢
kubectl get ep nginx-service
CoreDNS資訊驗證
登入任意Pod,執行ping命令,可以看到根據Service 名稱解析到了Service cluster ip
負載均衡驗證
登入任意 pod,執行curl nginx-service
,請求 service的 80 埠,會返回目標 pod名稱
以上我們講了什麼是服務發現,以及 k8s 的服務發現是怎麼實現的,希望對你有所幫助。