Service資源概述
建立Service資源
向Service對象請求服務
Service會話粘性
服務發現
服務暴露
Ingress和Ingress Controller
Ingress資源
Ingress控制器
Service是Kubernetes的核心資源類型之一,它通過規則定義出由多個Pod對象組合而成的邏輯集合,以及通路這組Pod的政策。
由Deployment等控制器管理的Pod對象在中斷或擴縮容後,Pod組合的IP位址都會發生變化,而引入Service資源後,就可以基于标簽選擇器将一組Pod定義成一個邏輯組合,并通過自己的IP位址和端口排程代理請求至組内的Pod對象之上,它向用戶端隐藏了真實的、處理使用者請求的Pod資源,使得用戶端的請求看上去就像是由Service直接處理并進行響應的一樣。而且Service與Pod對象之間通過标簽選擇器以松耦合的方式關聯,它可以先于Pod對象建立而不會發生錯誤。
Service資源基本的配置清單:
Service資源myapp-svc通過标簽選擇器關聯至标簽為“app=myapp”的各Pod對象,它會自動建立名為myapp-svc的Endpoints資源對象,并自動配置一個ClusterIP,暴露的端口由port字段進行指定,後端各Pod對象的端口則由targetPort給出。
分别檢視service和endpoint的狀态:
Service資源的預設類型為ClusterIP,它僅能接收來自于叢集中的Pod對象中的用戶端程式的通路請求。是以為了測試,會建立一個專用的Pod對象,利用其互動式接口來通路service資源。
啟動了一個運作CirrOS容器的Pod,CirrOS是設計用來進行雲計算環境測試的Linux微型發行版,它自帶HTTP用戶端工具curl等。
在容器的互動式接口通路ClusterIP:Port
Kubernetes叢集預設的Service代理模式為iptables,而且使用随機排程算法,是以Service會将用戶端請求随機排程至與其關聯的某個後端Pod資源上。
Service資源還支援Session affinity(會話粘性)機制,它能夠将來自同一個用戶端的請求始終轉發至同一個後端的Pod對象,适用于需要基于用戶端身份儲存某些私有資訊,并根據這些私有資訊追蹤使用者的活動等一類的需求。
Service資源通過spec.sessionAffinity和spec.sessionAffinityConfig兩個字段配置粘性會話:
sessionAffinity字段用于定義要使用的粘性會話的類型,它僅支援使用“None”和“ClientIP”兩種屬性值。
None:不使用sessionAffinity,預設值。
ClientIP:基于用戶端IP位址識别用戶端身份,把來自同一個源IP位址的請求始終排程至同一個Pod對象。
sessionAffinityConfig用于配置其會話保持的時長,其可用的時長範圍為“1~86400”,預設為10800秒
但是Service資源的Session affinity機制僅能基于用戶端IP位址識别用戶端身份,它會把經由同一個NAT伺服器進行源位址轉換的所有用戶端識别為同一個用戶端,排程粒度粗糙且效果不佳,是以實踐中并不推薦使用此種方法實作粘性會話。
Service為Pod中的服務類應用提供了一個穩定的通路入口,但Pod用戶端中的應用如何得知某個特定Service資源的IP和端口呢,這就需要借助服務發現機制來進行。
服務發現機制的基本實作,一般是事先部署好一個網絡位置較為穩定的服務注冊中心(也稱為服務總線),服務提供者(服務端)向注冊中心注冊自己的位置資訊,并在變動後及時予以更新,服務消費者則周期性地從注冊中心擷取服務提供者的最新位置資訊進而“發現”要通路的目标服務資源。
在K8S中可以基于CoreDNS進行服務發現,甚至也可以使用簡單的環境變量方式。
Service的IP位址預設僅在叢集内可達,叢集外部想通路服務,需要首先進行服務的暴露。
Service有四種類似ClusterIP、NodePort、LoadBalancer和ExternalName
ClusterIP:通過叢集内部IP位址暴露服務,此位址僅在叢集内部可達,而無法被叢集外部的用戶端通路;
NodePort:建立在ClusterIP類型之上,其在每個Node的IP位址的某靜态端口(NodePort)暴露服務,NodePort的路由目标為ClusterIP,簡單來說,NodePort類型就是在工作節點的IP位址上選擇一個端口用于将叢集外部的使用者請求轉發至目标Service的ClusterIP和Port,這種類型的Service既可如ClusterIP一樣受到叢集内部用戶端Pod的通路,也會受到叢集外部用戶端通過套接字NodeIP:NodePort進行的請求;
LoadBalancer:建構在NodePort類型之上,其通過cloud provider提供的負載均衡器将服務暴露到叢集外部,LoadBalancer類型的Service會指向關聯至Kubernetes叢集外部的某個負載均衡裝置,該裝置通過工作節點之上的NodePort向叢集内部發送請求流量,這種Service的優勢在于,能夠把來自于叢集外部用戶端的請求排程至所有節點(或部分節點)的NodePort之上,而不是依賴于用戶端自行決定連接配接至哪個節點,進而避免了因用戶端指定的節點故障而導緻的服務不可用;
ExternalName:通過将Service映射至由externalName字段的内容指定的主機名來暴露服務,此主機名需要被DNS服務解析至CNAME類型的記錄。這種類型并非定義由Kubernetes叢集提供的服務,而是把叢集外部的某服務以DNS CNAME記錄的方式映射到叢集内,進而讓叢集内的Pod資源能夠通路外部的Service的一種實作方式,這種類型的Service沒有ClusterIP和NodePort,也沒有标簽選擇器用于選擇Pod資源。
NodePort型的Service資源,其配置清單與前面預設的ClusterIP類型類似,隻是要顯式地在spec下指定<code>type: NodePort</code>
此外還可以指定Node端口,但必須在30000-32767之間,而且推薦使用叢集自動配置設定的端口以避免端口的沖突。
NodePort類型的Service資源雖然能夠于叢集外部通路得到,但外部用戶端必須得事先得知NodePort和叢集中至少一個節點的IP位址,且標明的節點發生故障時,用戶端還得自行選擇請求通路其他的節點,此外有時節點并不允許外界通路,LoadBalancer類型可将請求流量排程至各節點的NodePort之上。
建立LoadBalancer類型需要指定<code>type: LoadBalancer</code>,
ExternalName類型的Service資源用于将叢集外部的服務釋出到叢集中以供Pod中的應用程式通路。需要指定<code>type: ExternalName</code>和externalName,比如<code>externalName: redis.ilinux.io</code>,externalName屬性定義了一個CNAME記錄用于傳回外部真正提供服務的主機的别名,而後通過CNAME記錄值擷取到相關主機的IP位址。
服務建立後通過serviceName通路相應的服務,ClusterDNS會将此名稱以CNAME格式解析為spec.externalName字段中的名稱,而後通過DNS服務将其解析為相應的主機的IP位址。
在Kubernetes中,Service資源和Pod資源的IP位址僅能用于叢集網絡内部的通信,所有的網絡流量都無法穿透邊界路由器以實作叢集内外通信。Kubernetes提供了兩種内建的雲端負載均衡機制(cloud loadbalancing)用于釋出公共應用:
一種是工作于傳輸層的Service資源,它實作的是“TCP負載均衡器”,無論是iptables還是ipvs模型的Service資源都配置于Linux核心中的Netfilter之上進行四層排程,是一種類型更為通用的排程器,支援排程HTTP、MySQL等應用層服務。
但由于工作于傳輸層而功能有局限,比如不支援基于URL的請求排程機制,而且Kubernetes也不支援為其配置任何類型的健康檢查。
另一種便是Ingress資源,它實作的是“HTTP(S)負載均衡器”,屬于應用層負載均衡機制的一種,它提供了諸如可自定義URL映射和TLS解除安裝等功能,并支援多種類型的後端伺服器健康狀态檢查機制。
Ingress是Kubernetes API的标準資源類型之一,它其實就是一組基于DNS名稱(host)或URL路徑把請求轉發至指定的Service資源的規則,用于将叢集外部的請求流量轉發至叢集内部完成服務釋出,它僅是一組路由規則的集合,Ingress控制器根據這些規則來比對并路由請求流量。
Ingress資源是基于HTTP虛拟主機或URL的轉發規則。Ingress資源的定義方式舉例:
spec字段下主要嵌套如下三個字段
rules,用于定義目前Ingress資源的轉發規則清單;未由rules定義規則,或者沒有比對到任何規則時,所有流量都會轉發到由backend定義的預設後端。
backend,預設的後端用于服務那些沒有比對到任何規則的請求;定義Ingress資源時,至少應該定義backend或rules兩者之一;此字段用于讓負載均衡器指定一個全局預設的後端。backend對象的定義由兩個必選的内嵌字段組成:serviceName和servicePort,分别用于指定流量轉發的後端目标Service資源的名稱和端口。
tls,TLS配置,目前僅支援通過預設端口443提供服務;如果要配置指定的清單成員指向了不同的主機,則必須通過SNI TLS擴充機制來支援此功能。
單Service資源型Ingress
暴露單個Service的方法可以使用NodePort、LoadBalancer,也可以使用Ingress來暴露服務,隻需要為Ingress指定“default backend”,這樣Ingress控制器會為其配置設定一個IP位址接入請求流量,并将它們轉至指定的後段service,如:
基于URL路徑進行流量分發
Ingress也支援基于URL路徑進行流量分發,如:
上面定義的規則會将對www.ilinux.io/web的請求轉發到前端service myapp-svc-web,而将www.ilinux.io/api請求轉發到後段service myapp-svc-api。
基于主機名稱的虛拟主機
如果服務按照域名進行劃分,可以将Ingress基于虛拟主機定義如下:
TLS類型的Ingress資源
如果需要以HTTPS釋出Service資源,也可以配置TLS協定的Ingress資源,但需要基于一個含有私鑰和證書的Secret對象,這在後面的章節會涉及到,在Ingress資源中引用此Secret即可讓Ingress控制器加載并配置為HTTPS服務:
Ingress控制器自身是運作于Pod中的容器應用,一般是Nginx或Envoy一類的具有代理及負載均衡功能的守護程序,它監視着來自于API Server的Ingress對象狀态,并以其規則生成相應的應用程式專有格式的配置檔案并通過重載或重新開機守護程序而使新配置生效。例如,對于Nginx來說,Ingress規則需要轉換為Nginx的配置資訊。
既然Ingress控制器實際上也是Pod資源,那麼也需要接入外部流量,這可以使用NodePort或LoadBalancer類型的Service對象為其接入叢集外部的請求流量;或者借助于DaemonSet控制器,将Ingress控制器的Pod資源各自以單一執行個體的方式運作于叢集的所有或部分工作節點之上,并配置這類Pod對象以hostPort或hostNetwork的方式在目前節點接入外部流量。
以部署ingress-nginx并通過專用的Service接入流量為例:
首先apply線上的mandatory.yaml來部署ingress-nginx所需的全部資源,它們的namespace:為ingress-nginx:
然後定義專用的NodePort型Service資源,注意其selector要與nginx-ingress-controller的selector保持一緻:
然後就可以通過這個NodePort型Serviced的IP:30002通路了。或者也可以根據ingress指定的host名稱配置etc/hosts,比如對于如下的ingress配置:
<code>sudo vim /etc/hosts</code>,添加一行
然後也就可以通過tomcat.ilinux.io:30002通路了。
《Kubernetes實戰進階》 馬永亮著