Kubernetes Ingress簡單入門

不知道你是否注意到一個(gè)奇怪的現(xiàn)象,盡管Kubernetes Ingress API仍然處于beta狀態(tài),但是已經(jīng)有許多公司使用它來暴露Kubernetes服務(wù)。從事相關(guān)項(xiàng)目的工程師表示,Kubernetes Ingress API越來越有可能摘下其beta標(biāo)簽。實(shí)際上,Kubernetes Ingress API處于beta狀態(tài)已經(jīng)持續(xù)了幾年的時(shí)間,準(zhǔn)確來說,是在2015年秋季開始進(jìn)入該階段的。但是,漫長的beta階段可以讓Kubernetes貢獻(xiàn)者有時(shí)間來完善規(guī)范并使其與已經(jīng)搭建好的實(shí)施軟件(HAProxy、NGINX、Traefik等)保持一致,從而使API標(biāo)準(zhǔn)化以反映最常見并且有需求的功能。
隨著該功能GA的臨近,那么現(xiàn)在應(yīng)該是一個(gè)合適的時(shí)機(jī)可以幫助新手快速了解Ingress的工作方式。簡而言之,Ingress是一個(gè)規(guī)則,可以繪制出在集群內(nèi)部的服務(wù)如何彌合鴻溝,暴露到客戶可以使用它的外部世界。同時(shí),稱為Ingress controller的代理在集群網(wǎng)絡(luò)的邊緣進(jìn)行偵聽(監(jiān)視要添加的規(guī)則),并將每個(gè)服務(wù)映射到特定的URL路徑或域名以供公眾使用。在Kubernetes維護(hù)者開發(fā)API的同時(shí),其他開源項(xiàng)目也實(shí)現(xiàn)了Ingress Controller并為其代理添加了自己的獨(dú)特功能。
在本文中,我將介紹這些概念,并幫助你了解Ingress模式背后的驅(qū)動力。

路由問題
在Kubernetes中創(chuàng)建Pod時(shí),需要為其分配selector標(biāo)簽,如Deployment manifest的以下片段所示:

該Deployment創(chuàng)建了運(yùn)行Docker鏡像my-app的三個(gè)副本,并為其分配app=foo標(biāo)簽。除了直接訪問Pod,通常將它們分組在Service下,這使它們可以在單個(gè)集群IP地址上使用(但是只能在同一集群中使用)。Service充當(dāng)抽象層,隱藏了pod的周期短暫特性,可以隨時(shí)增加或減少或替換它們。它還可以執(zhí)行基本的循環(huán)負(fù)載均衡。
例如,以下Service定義收集所有帶有selector標(biāo)簽app = foo的Pod,并在其中平均路由流量。

但是,只能從集群內(nèi)部以及運(yùn)行在附近的其他Pod訪問此服務(wù)。Kubernetes Operator正在努力解決如何為集群外部的客戶端提供訪問權(quán)限。該問題在早期就已經(jīng)出現(xiàn),并且將兩種機(jī)制直接集成到Service規(guī)范中進(jìn)行處理。編寫service manifest時(shí),包括一個(gè)名為type的字段,該字段的值為NodePort或LoadBalancer。這是一個(gè)將類型設(shè)置為NodePort的示例:

NodePort類型的服務(wù)使用起來很簡單。本質(zhì)上,這些服務(wù)希望Kubernetes API為他們分配一個(gè)隨機(jī)的TCP端口,并將其暴露到集群之外。這樣做的方便之處在于,客戶端可以使用該端口將集群中的任何節(jié)點(diǎn)作為目標(biāo),并且他們的消息將被中轉(zhuǎn)到正確的位置。這就類似于你可以撥打美國境內(nèi)的任何電話,而接聽電話的人都會確保為你轉(zhuǎn)接到合適的人。
缺點(diǎn)在于,該端口的值必須介于30000到32767之間,雖然這個(gè)范圍安全地避開了常用端口地范圍,但是與常見的HTTP端口80和HTTPS 443相比,該端口顯然不是很標(biāo)準(zhǔn)。此外,隨機(jī)性本身也是一個(gè)障礙,因?yàn)樗馕吨闶孪炔恢乐凳鞘裁?,這使得配置NAT、防火墻規(guī)則更具挑戰(zhàn)性——尤其是需要為每項(xiàng)服務(wù)設(shè)置不同的隨機(jī)端口。
另一個(gè)選項(xiàng)是將類型設(shè)置為LoadBalancer。但是,這有一些前提條件——僅當(dāng)你在GKE或EKS之類的云托管環(huán)境中運(yùn)行并且可以使用該云供應(yīng)商的負(fù)載均衡器技術(shù)時(shí),它才有效,因?yàn)樗亲詣舆x擇并配置的。其缺點(diǎn)是比較昂貴,因?yàn)槭褂眠@種類型的服務(wù)會為每個(gè)服務(wù)啟動一個(gè)托管的負(fù)載均衡器以及一個(gè)新的公共IP地址,這會產(chǎn)生額外的費(fèi)用。
Ingress路由
分配一個(gè)隨機(jī)端口或外部負(fù)載均衡器是很容易操作的,但也帶來了獨(dú)特的挑戰(zhàn)。定義許多NodePort服務(wù)會造成隨機(jī)端口混亂,而定義許多負(fù)載均衡器服務(wù)會導(dǎo)致需要支付比實(shí)際所需更多的云資源費(fèi)用。這些情況不可能完全避免,但也許可以減少它的使用范圍,甚至你只需要分配1個(gè)隨機(jī)端口或1個(gè)負(fù)載均衡器就能夠暴露許多內(nèi)部服務(wù)。因此,這一平臺需要一個(gè)新的抽象層,該層可以在入口點(diǎn)(entrypoint)后面整合許多服務(wù)。
那時(shí),Kubernetes API引入了一種稱為Ingress的新型manifest,它為路由問題提供了新的思路。它的工作方式是這樣的:你編寫一個(gè)Ingress manifest,聲明你希望客戶端如何路由到服務(wù)。manifest實(shí)際上并不自行執(zhí)行任何操作,你必須將Ingress Controller部署到你的集群中,以監(jiān)視這些聲明并對其執(zhí)行操作。
與其他任何應(yīng)用程序一樣,Ingress controller是Pod,因此它們是集群的一部分并且可以看到其他Pod。它們是使用在市場上已經(jīng)發(fā)展了多年的反向代理搭建的,因此,你可以選擇HAProxy Ingress Controller、NGINX Ingress Controller等。底層代理為其提供了第7層路由和負(fù)載均衡功能。不同的代理將自己的功能集放到表中。例如,HAProxy Ingress Controller不需要像NGINX Ingress Controller那樣頻繁地重新加載,因?yàn)樗鼮榉?wù)器分配了slot,并使用Runtime API在運(yùn)行時(shí)填充slot。這使得該Ingress Controller擁有更好的性能。
Ingress Controller本身位于集群內(nèi)部,與其他Kubernetes Pod一樣,也容易受到同一“監(jiān)獄”的“監(jiān)禁”。你需要通過NodePort或LoadBalancer類型的服務(wù)將它們暴露到外部。但是,現(xiàn)在你只有一個(gè)入口點(diǎn),所有流量都將通過此處:一個(gè)服務(wù)連接到一個(gè)Ingress Controller,Ingress Controller依次連接到許多內(nèi)部Pod。Controller具有檢查HTTP請求的功能,可以根據(jù)其發(fā)現(xiàn)的特征(例如URL路徑或域名)將客戶端定向到正確的Pod。
參考這個(gè)Ingress的示例,該示例定義了URL路徑/foo應(yīng)該如何連接到名為foo-service的后端服務(wù),而URL路徑/bar被定向到名稱為bar-service的服務(wù)。

如上文所示,你依舊需要為你的Pod設(shè)置服務(wù),但是你不需要在Pod上設(shè)置類型字段,因?yàn)槁酚珊拓?fù)載均衡將由Ingress層處理。服務(wù)的作用被簡化為以通用名稱對Pod進(jìn)行分組。最終,兩個(gè)路徑,/foo和/bar,將由一個(gè)公共IP地址和域名提供服務(wù),例如example.com/foo和example.com/bar。本質(zhì)上,這是API網(wǎng)關(guān)模式,在API網(wǎng)關(guān)中,單個(gè)地址將請求路由到多個(gè)后端應(yīng)用程序。
添加Ingress Controller
Ingress manifest的聲明式方法是你可以指定所需的內(nèi)容,而無需知道如何實(shí)現(xiàn)。Ingress Controller的工作之一是執(zhí)行,它需要監(jiān)控新的ingress規(guī)則并配置其底層代理以制定相應(yīng)的路由。
你可以使用Kubernetes包管理工具Helm安裝HAProxy Ingress Controller。首先,通過下載Helm二進(jìn)制文件并將其復(fù)制到PATH環(huán)境變量中包含的文件夾(例如/usr/local/bin/)中來安裝Helm。接下來,添加HAProxy Technologies Helm庫,并使用helm install命令部署Ingress Controller。

通過運(yùn)行命令kubectl get service列出所有正在運(yùn)行的服務(wù)來驗(yàn)證是否已創(chuàng)建Ingress Controller。

HAProxy Ingress Controller在集群的pod中運(yùn)行,并使用NodePort類型的Service資源發(fā)布對外部客戶端的訪問。在上面顯示的輸出中,你可以看到為HTTP選擇了端口31704,為HTTPS選擇了端口32255。你還可以在端口30347上查看HAProxy信息統(tǒng)計(jì)頁面。HAProxy Ingress Controller會提供有關(guān)流經(jīng)它的流量的詳細(xì)指標(biāo),因此你可以更好地觀察到進(jìn)入集群的流量。
在controller創(chuàng)建類型為NodePort的服務(wù)時(shí),這意味著需要分配一個(gè)隨機(jī)的端口并且端口編號往往很高,但是現(xiàn)在你只需管理幾個(gè)此類端口,也就是只需管理連接到Ingress Controller的端口,無需再為每個(gè)服務(wù)創(chuàng)建一個(gè)端口。你也可以將其配置為使用LoadBalancer類型,只要在云端進(jìn)行操作即可。它看起來如下:

總體而言,不需要管理太多Ingress Controller。安裝后,它基本上會在后臺執(zhí)行其工作。你只需要定義Ingress manifest,controller就會立即將它們連接起來。Ingress manifest的定義與引用的服務(wù)有所區(qū)別,因此你可以控制何時(shí)暴露服務(wù)。
結(jié) 論
Ingress資源通過允許API網(wǎng)關(guān)樣式的流量路由,整合了外部客戶端如何訪問Kubernetes集群中的服務(wù)。代理服務(wù)通過公共入口點(diǎn)(entrypoint)進(jìn)行中轉(zhuǎn),你可以使用intent-driven、YAML聲明來控制何時(shí)以及如何公開服務(wù)。
當(dāng)Ingress API這一功能GA之后,你一定會看到這種模式變得越來越流行。當(dāng)然,可能產(chǎn)生一些細(xì)微的變化,主要是為了使API與現(xiàn)有controller中已經(jīng)實(shí)現(xiàn)的功能保持一致。其他改進(jìn)可能會指導(dǎo)controller如何繼續(xù)發(fā)展以符合Kubernetes維護(hù)者的愿景??偠灾?,現(xiàn)在是開始使用此功能的好時(shí)機(jī)!