KubeSphere 項目網關與應用路由提供了一種聚合服務的方式,將集群的內部服務通過一個外部可訪問的 IP 地址以 HTTP 或 HTTPs 暴露給集群外部。應用路由定義了這些服務的訪問規則,用戶可以定義基於 host 主機名稱和 URL 匹配的規則。同時還可以配置 HTTPs offloading 等選項。項目網關則是應用路由的具體實現,它承載了流量的入口並根據應用路由規則將匹配到的請求轉發至集群內的服務。
整體架構
用戶的服務和應用路由的架構密不可分,因此我們需要結合用戶服務來理解項目網關的整體架構。一個典型生產環境中,項目網關架構如下圖所示:
圖中組件共分為四個部分:
Nginx Ingress Controller
是應用網關的核心組件。KubeSphere 項目網關基於Nginx Ingress Controller
實現,它通過獲Ingress
對象生成 Nginx 反向代理規則配置並配置應用於 Nginx 服務。應用路由是一個Ingress
對象。應用網關依賴於Service
對外暴露 Nginx 服務,因此Service
在生產環境中一般設置為LoadBalancer
類型,由雲服務商配置其公有雲 IP 地址及外部負載均衡器,用以保障服務的高可用性。- 外部負載均衡器,應用網關的
Service
生成的外部負載均衡器,一般由各個雲服務商提供。因此每種負載均衡器的特性有很多差別,比如 SLA、帶寬、IP 配置等等。我們一般可以通過服務商提供的注解對其進行配置,在設置網關時,我們通常需要了解這些特性。 - DNS 域名解析服務, 一般由域名服務商提供服務,我們可以配置域名解析紀錄將域名指向
LoadBalancer
的公網 IP。如果子域名也指向同一 IP,我們可以可使用泛域名解析方式。 - 用戶服務與應用路由,用戶需要為應用程序創建
Service
用於暴露集群內的服務,然后創建應用路由對外暴露服務。注,Nginx Ingress Controller
並不通過Kube-proxy
訪問服務 IP。它通過服務查找與之關聯POD
的EndPoint
,並將其設置為Nginx
的Upstream
。Nginx 直接連接POD
可以避免由Service
帶來的額外網絡開銷。
應用路由 vs Service(type=LoadBalancer)
在實踐過程中,應用路由與 Service
的應用場景常常令人混淆。它們都可以向集群外暴露集群內服務,並提供負載均衡功能。並且應用路由看起來也是依賴於服務的,那么他們究竟有何區別呢?這個問題我們需要從以下幾個角度理解。
Service
最初的設計動機是將某個服務的后端(Pod)進行抽象並公開為網絡服務。它通常是以一個服務為單位的,所有后端均運行相同的服務端。而應用路由
的設計目標是對 API 對象進行管理。它雖然也可以暴露一個服務,但是它更強大的功能在於其可以將一系列服務進行聚合,對外提供統一的訪問 IP、域名、URL 等。Service
工作在 TCP/IP 協議的第四層,因此它使用IP+端口+協議
三元組作為服務的唯一標識。因此當我們需要暴露一個服務時,它不能與其他已存在的服務沖突。例如,我們暴露基於 HTTP/HTTPs 的服務時,通常這類服務都會占用 80、443 端口,為了避免端口沖突,就需要為每個暴露的服務申請一個獨立的 IP 地址,導致資源浪費。應用路由
工作在七層,所有通過應用路由暴露的服務都可以共享項目網關的 IP 地址和 80、443 端口。每個應用路由
使用Host+URL
作為服務的唯一標識,將 HTTP 請求轉發到后端服務中。Service
支持 TCP 與 UDP 協議並且對上層協議沒有限制,而應用路由目前只支持 HTTP/HTTPs 或 HTTP2 協議,無法轉發基於 TCP 或 UDP 的其他協議。
結合以上三點,我們不難得看出:應用路由更適用於使用 HTTP 協議的微服務架構的場景中,而 Service
雖然對 HTTP 協議沒有深度的支持,但是它可以支持更多其他協議。
應用路由 vs Spring Cloud Gateway 或 Ocelot
Java、.net Core 的開發人員對 Spring Cloud Gateway
或 Ocelot
一定不會感到陌生,他們是各自語言領域中最常用的 API 網關。那么到我們是否可以直接使用這些網關呢?理解這個問題,我們首先要知道什么是 API 網關,在 Wiki 百科中 API Gateway
並沒有一個明確的定義,但我們從各個大廠的服務說明中可以得出一個基本的結論:
API 網關作為用戶與后端服務之間的唯一入口管理后端服務,即 API 網關提供了一個方向代理服務將后端服務進行聚合,將客戶端請求路由到后端服務並將結果返回給客戶端。同時,API 網關可提供身份認證、監控、負載均衡、HTTPS offloading 等高級功能。
因此,應用路由承擔了 API 網關的職責,即它與 Spring Cloud Gateway
或 Ocelot
等 API 網關具有同等地位。諸如 Spring Cloud Gateway
類的 API 網關通過 Service
的方式暴露到集群外部也可替代部分應用路由功能。我們接下做一個簡要的對比,並分析一下他們的優缺點:
- 作為應用網關的基本職責,它們均具有路由轉發功能。並且以上提到的網關均支持基於 HOST、URL 的路由轉發規則設置。
- 服務注冊與發現,
Spring Cloud Gateway
等全家桶式解決方案提供了非常豐富的支持選項,對於 java 開發者更為友好,網關上的服務均可通過注冊中心服務無縫銜接。而 Ocelot 雖然未內置服務發現與注冊方案,但是可以通過 Ocelot + Consul 的方式實現。對比之下 Kubernetes 集群中部署應用,一般采用基於 DNS 的服務發現方式,但並沒有為客戶端提供一個統一的服務注冊發現方式。對外暴露的服務需要顯示的創建 Ingress 規則。相比之下Spring Cloud Gateway
類的 API 網關使用相同技術棧,這可以極大的簡化開發人員的學習成本。 - 通用性上,Ingress 是雲原生背景下 Kubernetes 社區定義的 API 管理規范。KubeSphere 默認采用
Nginx Ingress Controller
實現。同時我們可以使用任何兼容的第三方 Ingress 控制器進行替換。Ingress 中只定義了基本共性的功能,但網關通常會提供日志、監控、安全等更多通用的運維工具。相比之下,與語言緊密結合的 API 網關通常與開發平台進行綁定,語言相互替代性較差(不願引入更多技術棧或無客戶端集成支持)。功能相對固定,但大多提供了良好的插件機制,開發人員使用自己熟悉的語言進行拓展。 - 性能方面,毋庸置疑,以基於 Nginx 的 Ingress Controller 為代表的通用型 API 網關,比
Spring Cloud Gateway
、Ocelot
等有非常明顯的性能優勢。
總體來講,每種網關都有其優缺點或局限性。在項目初期應首先考慮應用網關的架構。在基於雲原生的場景下,應用路由會是一個不錯的選擇。而如果您的團隊依賴於開發技術棧,那么常用技術棧中的 API 網關通常也會作為首選。但這並不意味着它們必須進行二選一,在一些復雜場景下我們可以結合二者的優勢,開發人員使用自己熟知的 API 網關用於服務聚合、認證鑒權等功能,同時在其前方放置應用網關實現日志監控,負載均衡,HTTPs offloading 等工作。
微軟官方微服務架構示例 eShopOnContainers 即采用了該種混合架構。
動手實戰
理解以上應用場景和整體架構后,我們接下來演示如何在 KubeSphere 中配置項目網關和應用路由。以下內容將基於 Weaveworks 的微服務演示項目 SockShop 實現。SockShop 是一個典型的前后端分離架構,它由前端服務 front-end
和若干后端服務 catalogue
、carts
、orders
等組成。在當前架構下,front-end
除了承擔靜態頁面服務的功能,還承擔了后端 API 代理轉發的任務。我們假設以下場景,即由 Nodejs 轉發 API 造成服務異步阻塞,從而影響頁面性能。因此我們決定使用 ingress 直接轉發服務 catalogue
用以提升性能。下面我們看一下詳細配置步驟。
准備工作
- 在部署 SockShop 之前,我們首先要配置一個用於演示的企業空間
workspace-demo
和項目sock-shop
。具體步驟請參考《創建企業空間、項目、帳戶和角色》
- 完成項目
sock-shop
的創建后,我們接下來使用kubectl
部署 SockShop 的相關服務。您可以使用本地的控制台或 KubeSphere web 工具箱中的kubectl
執行以下命令。
kubectl -n sock-shop apply -f https://github.com/microservices-demo/microservices-demo/raw/master/deploy/kubernetes/complete-demo.yaml
執行過后可以進入 sock-shop
的工作負載
頁面查看部署的狀態,等待所有的部署都正常運行后,我們再進行下一步操作。
項目網關配置
-
進入
sock-shop
項目,從左側導航欄進入項目設置下的高級設置頁面,然后點擊設置網關。 -
在接下來彈出的對話框中,需要根據 KubeSphere 的安裝環境進行設置。如果您使用的是本地開發環境或私有環境可以選擇
NodePort
的方式暴露網關。如果是托管 Kubernetes 雲服務,一般選擇 LoadBalancer。
應用路由配置
- 首先,我們選擇左側導航欄應用負載中的應用路由,點擊右側的創建。在基本信息中填寫名稱
frontend
。在路由規則中,添加一條新的規則。由於是演示項目,我們使用自動生成模式。KubeSphere 自動以<服務名稱>.<項目名稱>.<網關地址>.nip.io 格式生成域名,該域名由 nip.io 自動解析為網關地址。在路徑、服務、端口上依次選擇 "/"、"front-end"、"80"。點擊下一步后,繼續點擊創建。
- 路由創建完成后,可以在應用路由列表頁面點擊
frontend
進入詳情。並在規則中可以點擊點擊訪問訪問按鈕。在新的瀏覽器 tab 下,應該出現如下的網站:
- 為了與下面的步驟進行對比,我們在 SockShop 的網站頁面打開調試功能查看網絡請求,以 Chrome 為例只需點擊鍵盤的F12鍵。刷新一下頁面后我們找到如下
catalogue
API 請求:
該請求頭中的 X-Powered-By:Express
表明了這條請求是由前端的 Nodejs 應用轉發。
- 接下來,在
frontend
的詳情頁面點擊左側的更多操作,並選擇編輯規則。在彈出的編輯規則頁面,選擇剛剛增加的規則,並點擊左側的編輯圖標。新增一條路徑,在路徑、服務、端口上依次選擇"/catalogue"、"catalogue"、"80"。保存該設置。編輯后的規則如下:
- 我們再次訪問 SockShop 的網站頁面,該頁面並沒有任何變化。我們使用瀏覽器調試器,再次查看網絡請求,
catalogue
的請求如下:
我們發現該請求已經沒有了 X-Powered-By:Express
請求頭,這說明了我們上面應用的規則已經生效,catalogue
相關的 API 請求已經通過應用路由直接轉發 catalogue
服務了,而不需要再通過 fron-tend
服務進行中轉。以上的配置我們利用了路由規則的最長匹配規則。“/catalogue”比更路徑具有更高的優先級。
更多配置內容可以參考《應用路由》
總結
本篇內容簡述了應用路由的基本架構,並與 Kubernetes Service 及其他應用網關分別做了對比。最后通過 SockShop 這個案例講解的應用路由的配置方法。希望讀者對應用路由能有進一步的理解,根據應用的特性選擇合適的外部服務暴露方式。
本文由博客一文多發平台 OpenWrite 發布!