Service、Pod、Label、Endpoint、Kube-proxy、Cluster IP、LoadBalance、NodePort、環(huán)境變量、DNS、Expose
Service
微服務(wù)架構(gòu)的應(yīng)用需要有好的服務(wù)編排支持。k8s中的Service提供了一套簡(jiǎn)化的服務(wù)代理和發(fā)現(xiàn)機(jī)制,天然適應(yīng)微服務(wù)架構(gòu)。
Service定義了服務(wù)的入口地址。前端應(yīng)用(pod)通過(guò)入口地址訪問(wèn)其背后由pod副本組成的集群實(shí)例。service與其后端pod副本集群間通過(guò)label selector實(shí)現(xiàn)“無(wú)縫對(duì)接”。
負(fù)載均衡器,為這組pod開(kāi)啟對(duì)外服務(wù)端口,并且把這些pod的endpoint列表加入端口的轉(zhuǎn)發(fā)列表中,客戶端就可以通過(guò)負(fù)載均衡器的對(duì)外IP地址+服務(wù)端口來(lái)訪問(wèn)此服務(wù),而客戶端的請(qǐng)求由負(fù)載均衡器的算法來(lái)決定被轉(zhuǎn)發(fā)到哪個(gè)pod。
kube-proxy是軟件負(fù)載均衡器,負(fù)責(zé)把對(duì)service的請(qǐng)求轉(zhuǎn)發(fā)到后端的pod實(shí)例,并在內(nèi)部實(shí)現(xiàn)服務(wù)的負(fù)載均衡與會(huì)話保持機(jī)制。
每個(gè)service有全局唯一的虛擬IP地址,即cluster ip。這樣,每個(gè)服務(wù)就變成了具備唯一IP地址的“通信節(jié)點(diǎn)”,服務(wù)調(diào)用就變成了TCP網(wǎng)絡(luò)通信問(wèn)題。
pod的endpoint地址會(huì)隨著pod的銷毀和重新創(chuàng)建而發(fā)生改變,因?yàn)閜od的ip會(huì)變化。
pod的ip是在容器中配置。service的cluster ip是在iptables中配置,并映射到pod ip。iptables將訪問(wèn)service的流量使用類似輪詢的負(fù)載均衡策略轉(zhuǎn)發(fā)到后端pod。
除了通過(guò)cluster ip訪問(wèn)service,還可以通過(guò)DNS。
原理
在k8s中,受到RC調(diào)控的時(shí)候,Pod副本是變化的,對(duì)應(yīng)的虛擬IP也是變化的,比如發(fā)生遷移、伸縮或者更新的時(shí)候。k8s的Service是抽象概念,它定義了一組Pod邏輯集合以及訪問(wèn)它們的策略。Service的目標(biāo)是提供一種橋梁,為訪問(wèn)者提供一個(gè)固定訪問(wèn)地址,用于在訪問(wèn)時(shí)重定向到相應(yīng)的后端,這使得非k8s原生應(yīng)用程序,在無(wú)須為Kubemces編寫特定代碼的前提下,輕松訪問(wèn)后端。
需要注意的是,k8s分配給Service的固定IP是虛擬IP,并不是真實(shí)的IP,在外部是無(wú)法尋址。真實(shí)的系統(tǒng)實(shí)現(xiàn)上,k8s是通過(guò)kube-proxy組件來(lái)實(shí)現(xiàn)虛擬IP路由及轉(zhuǎn)發(fā)。ku-proxy組件是基于iptables實(shí)現(xiàn)路由轉(zhuǎn)發(fā)。
通過(guò)分析、識(shí)別并建模系統(tǒng)中的所有服務(wù)為微服務(wù)-----Kubernetes Service,最終系統(tǒng)由多個(gè)提供不同業(yè)務(wù)能力而又彼此獨(dú)立的微服務(wù)單元所組成,服務(wù)之間通過(guò)TCP/IP進(jìn)行通信。
service的訪問(wèn)ip和endpoint/pod ip都會(huì)在k8s的dns服務(wù)器里存儲(chǔ)域名和ip的映射關(guān)系。
Service代理外部服務(wù)
Service不僅可以代理Pod,還可以代理任意其他后端,比如運(yùn)行在k8s外部的Mysql、Oracle等。
無(wú)頭(headless)service沒(méi)有selector,這樣就不會(huì)創(chuàng)建相關(guān)的endpoints對(duì)象。再手動(dòng)將service映射到指定的endpoints,即通過(guò)定義兩個(gè)同名的service和endPoints來(lái)實(shí)現(xiàn)的。service抽象類訪問(wèn)pod,也能抽象其他類型的backend。
Service內(nèi)部負(fù)載均衡
當(dāng)Service的Endpoints包含多個(gè)IP的時(shí)候,即服務(wù)代理存在多個(gè)后端,將進(jìn)行請(qǐng)求的負(fù)載均衡。默認(rèn)的負(fù)載均衡策略是輪詢或者隨機(jī)(由kube-proxy的模式?jīng)Q定)。同時(shí),Service上通過(guò)設(shè)置Service-->spec-->sessionAffinity=ClientIP,來(lái)實(shí)現(xiàn)基于源IP地址的會(huì)話保持。
發(fā)布Service(service的種類)
Service的虛擬IP是由k8s虛擬出來(lái)的內(nèi)部網(wǎng)絡(luò),外部是無(wú)法尋址到的。但有些服務(wù)需要被外部訪問(wèn)到。這時(shí)就需要增加一層網(wǎng)絡(luò)轉(zhuǎn)發(fā),即外網(wǎng)到內(nèi)網(wǎng)的轉(zhuǎn)發(fā)。k8s提供了NodePort、LoadBalancer、Ingress三種方式。
- clusterIP(cluster內(nèi)部訪問(wèn)service)
Cluster中的pod可以通過(guò)serviceName.namespace_name訪問(wèn)service。在同一個(gè)namespace的可以省略namespace_name。 - nodePort(cluster外部訪問(wèn)service)
service通過(guò)cluster節(jié)點(diǎn)的靜態(tài)端口對(duì)外提供服務(wù)。cluster外部通過(guò)任意nodeIP+nodePort訪問(wèn)service。默認(rèn)端口范圍是30000-32767。 - loadbalancer
公有云平臺(tái)(例如GCE)的load balance對(duì)外提供服務(wù)。一些高級(jí)的L7轉(zhuǎn)發(fā)功能,例如基于HTTP header、cookie、URL的轉(zhuǎn)發(fā)就做不了。
service的自發(fā)現(xiàn)機(jī)制
k8s中有一個(gè)很重要的服務(wù)自發(fā)現(xiàn)特性。一旦service被創(chuàng)建,該service的IP和port等信息都可以被注入到pod中供它們使用。k8s支持兩種service發(fā)現(xiàn)機(jī)制:環(huán)境變量和DNS。
- 環(huán)境變量方式
k8s創(chuàng)建Pod時(shí)會(huì)自動(dòng)添加所有可用的service環(huán)境變量到該P(yáng)od中,如有需要,這些環(huán)境變量就被注入Pod內(nèi)的容器里。環(huán)境變量的注入只發(fā)生在Pod創(chuàng)建時(shí),且不會(huì)被自動(dòng)更新。這個(gè)特點(diǎn)暗含了service和訪問(wèn)該service的Pod的創(chuàng)建時(shí)間的先后順序。 - DNS方式
k8s集群支持DNS服務(wù)。這個(gè)DNS服務(wù)器使用k8s的watchAPI,不間斷的監(jiān)測(cè)新的service的創(chuàng)建并為每個(gè)service創(chuàng)建一個(gè)DNS記錄。如果DNS在整個(gè)集群范圍內(nèi)都可用,那么所有的Pod都能夠自動(dòng)解析service的域名。
服務(wù)發(fā)現(xiàn)用service的name與cluster ip地址做dns域名映射即可解決。
k8s通過(guò)add-on增值包的方式引入dns系統(tǒng),把服務(wù)名作為dns域名,程序使用服務(wù)名來(lái)建立通信連接。
多個(gè)service如何避免地址和端口沖突
k8s為service分配唯一的ClusterIP,所以當(dāng)使用ClusterIP:port的組合訪問(wèn)service的時(shí)候,這個(gè)組合一定不會(huì)發(fā)生重復(fù)。另一方面,kube-proxy為每個(gè)service真正打開(kāi)的是不會(huì)重復(fù)的隨機(jī)端口,用戶在service描述文件中指定的訪問(wèn)端口會(huì)被映射到這個(gè)隨機(jī)端口上。
service的不足
k8s使用iptables和kube-proxy解析service的人口地址,在中小規(guī)模的集群中運(yùn)行良好,但是當(dāng)service的數(shù)量超過(guò)一定規(guī)模時(shí),仍然有些問(wèn)題。首當(dāng)其沖的便是service環(huán)境變量泛濫,以及service與使用service的pod兩者創(chuàng)建時(shí)間先后的制約關(guān)系。目前來(lái)看,很多使用者在使用k8s時(shí)往往會(huì)開(kāi)發(fā)一套自己的Router組件來(lái)替代service,以便更好地掌控和定制這部分功能。
如果覺(jué)得通過(guò)yaml方式創(chuàng)建service比較麻煩,kubectl提供expose子命令直接將deployment暴露為服務(wù)。
參考
- 《Kubernetes 權(quán)威指南》
- 《每天5分鐘玩轉(zhuǎn)kubernetes》
- 《Kubernetes 權(quán)威指南-企業(yè)級(jí)容器云實(shí)踐》
- http://www.lxweimin.com/p/d53b5df16e92