對(duì)k8s有點(diǎn)了解技術(shù)人員,應(yīng)該都只知道k8s是有服務(wù)注冊(cè)發(fā)現(xiàn)的,今天就分析下這個(gè)原理,看看怎么實(shí)現(xiàn)的。
什么是服務(wù)注冊(cè)與發(fā)現(xiàn)
服務(wù)注冊(cè)與發(fā)現(xiàn)是一種機(jī)制,用于在集群中動(dòng)態(tài)地發(fā)現(xiàn)和連接不同的服務(wù),比如我們?cè)陂_發(fā)微服務(wù)時(shí),經(jīng)常使用的Eureka、Nacos等
Service B 把自己注冊(cè)到 Service Registry 叫做 服務(wù)注冊(cè)
Service A 從 Service Registry 發(fā)現(xiàn) Service B 的節(jié)點(diǎn)信息叫做 服務(wù)發(fā)現(xiàn)
K8s 中為什么需要服務(wù)發(fā)現(xiàn)
動(dòng)態(tài)性
在K8s集群中,Pod和服務(wù)的數(shù)量和位置都是動(dòng)態(tài)變化的,Pod有可能伸縮、重新部署或遷移,在這樣的環(huán)境下,如果硬編碼的服務(wù)地址是不可行的,所以服務(wù)注冊(cè)與發(fā)現(xiàn)使得我們的系統(tǒng)能夠自動(dòng)感知到這種變化。
透明性
服務(wù)注冊(cè)與發(fā)現(xiàn)使得我們的系統(tǒng)可以使用服務(wù)名稱來(lái)訪問(wèn)其他服務(wù),而不需要關(guān)心具體的IP地址和端口號(hào)。
負(fù)載均衡
通過(guò)服務(wù)注冊(cè)與發(fā)現(xiàn)可以實(shí)現(xiàn)負(fù)載均衡,將請(qǐng)求均勻地分發(fā)到多個(gè)后端服務(wù)實(shí)例。
容錯(cuò)性
當(dāng)服務(wù)實(shí)例發(fā)生故障或不可用時(shí),服務(wù)注冊(cè)與發(fā)現(xiàn)可以自動(dòng)檢測(cè)并從服務(wù)發(fā)現(xiàn)機(jī)制中移除不可用的實(shí)例。這樣,請(qǐng)求將被自動(dòng)路由到可用的實(shí)例上,提高應(yīng)用程序的容錯(cuò)性和可用性。
k8s 服務(wù)注冊(cè)發(fā)現(xiàn)原理
基于上面的介紹,我們了解到K8s中的Pod的生命周期是短暫的,他們的IP地址會(huì)不斷變化,如果讓服務(wù)消費(fèi)方去管理這些Pod IP在做負(fù)載均衡調(diào)用Pod,那么會(huì)很復(fù)雜,為了對(duì)外提供統(tǒng)一的入口來(lái)提供服務(wù),所以k8s創(chuàng)建了Service,不管是內(nèi)部還是外部統(tǒng)一調(diào)用 Service,然后再由 Service 轉(zhuǎn)發(fā)到后端Pod
Endpoints
Pod 的地址管理則由Endpoints管理,根據(jù)Service名稱可以查詢Endpoints信息,當(dāng)通過(guò)API創(chuàng)建/修改service對(duì)象時(shí),endpoints控制器的監(jiān)聽(tīng)到Service對(duì)象,然后根據(jù)Service的配置的選擇器創(chuàng)建一個(gè)endpoints對(duì)象,此對(duì)象將pod的IP、容器端口信息存儲(chǔ)到etcd中。
他們之間關(guān)系如下:
同時(shí)Endpoints控制器會(huì)監(jiān)聽(tīng)與Pod相關(guān)的事件,包括上下線事件,一旦Endpoints控制器接收到這些事件,它會(huì)相應(yīng)地更新Endpoints資源,將不可用的Pod從Endpoints列表中移除。
域名解析
由于Service的 IP有可能會(huì)變,如果在代碼里面寫死Service IP后期維護(hù)起來(lái)也是比較麻煩的事情,所以通過(guò)在創(chuàng)建一個(gè)Service時(shí),CoreDNS會(huì)為該Service添加一個(gè)域名解析記錄,將Service的名稱解析為相應(yīng)的Cluster IP地址。這樣其他Pod或服務(wù)可以通過(guò)使用Service名稱來(lái)訪問(wèn)該Service。
kube-proxy
kube-proxy 是集群中每個(gè)節(jié)點(diǎn)上運(yùn)行的網(wǎng)絡(luò)代理,它負(fù)責(zé)將集群內(nèi)部的Service暴露給其他Pod或外部網(wǎng)絡(luò)。它通過(guò)在Node節(jié)點(diǎn)上設(shè)置網(wǎng)絡(luò)規(guī)則和轉(zhuǎn)發(fā)規(guī)則,將Service的請(qǐng)求轉(zhuǎn)發(fā)到正確的目標(biāo)Pod
同時(shí)kube-proxy實(shí)現(xiàn)負(fù)載均衡算法,將進(jìn)入Service的請(qǐng)求均勻地分發(fā)到后端的Pod實(shí)例。這確保了在多個(gè)副本的情況下,Service能夠平衡地處理請(qǐng)求,提高可用性和性能。
kube-proxy 通過(guò)監(jiān)聽(tīng)知道了Service、endpoints對(duì)象的創(chuàng)建,然后把Service的CLUSTER-IP 和端口信息拿出來(lái),創(chuàng)建iptables NAT規(guī)則做轉(zhuǎn)發(fā)或通過(guò)ipvs模塊創(chuàng)建VS服務(wù)器,這樣經(jīng)過(guò)CLUSTER-IP的流量都被轉(zhuǎn)發(fā)到后端pod。
當(dāng)Service的目標(biāo)Pod位于同一節(jié)點(diǎn)上時(shí),kube-proxy會(huì)將請(qǐng)求直接轉(zhuǎn)發(fā)到該節(jié)點(diǎn)上的Pod,而不會(huì)跨節(jié)點(diǎn)轉(zhuǎn)發(fā)。這種情況下,請(qǐng)求不會(huì)被發(fā)送到其他節(jié)點(diǎn)上。
然而,如果Service的目標(biāo)Pod分布在多個(gè)節(jié)點(diǎn)上,kube-proxy可以通過(guò)負(fù)載均衡算法將請(qǐng)求轉(zhuǎn)發(fā)到其他節(jié)點(diǎn)上的Pod。
示例演示
下面我們基于兩個(gè)配置文件,驗(yàn)證下上面的結(jié)論
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,訪問(wèn)pod時(shí)會(huì)返回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
我們依次執(zhí)行以上兩個(gè)文件,最后獲取到信息如下
Service地址查看
kubectl get svc nginx-service
Pod信息查看
kubectl get pods -l app=nginx -o wide
Endpoints信息查看
根據(jù)service名稱查詢
kubectl get ep nginx-service
CoreDNS信息驗(yàn)證
登錄任意Pod,執(zhí)行ping命令,可以看到根據(jù)Service 名稱解析到了Service cluster ip
負(fù)載均衡驗(yàn)證
登錄任意 pod,執(zhí)行curl nginx-service,請(qǐng)求 service的 80 端口,會(huì)返回目標(biāo) pod名稱
以上我們講了什么是服務(wù)發(fā)現(xiàn),以及 k8s 的服務(wù)發(fā)現(xiàn)是怎么實(shí)現(xiàn)的,希望對(duì)你有所幫助。