深入淺出 Kubernetes 項目網關與應用路由

KubeSphere 項目網關與應用路由提供了一種聚合服務的方式,將集羣的內部服務通過一個外部可訪問的 IP 地址以 HTTP 或 HTTPs 暴露給集羣外部。應用路由定義了這些服務的訪問規則,用戶可以定義基於 host 主機名稱和 URL 匹配的規則。同時還可以配置 HTTPs offloading 等選項。項目網關則是應用路由的具體實現,它承載了流量的入口並根據應用路由規則將匹配到的請求轉發至集羣內的服務。

整體架構

用戶的服務和應用路由的架構密不可分,因此我們需要結合用戶服務來理解項目網關的整體架構。一個典型生產環境中,項目網關架構如下圖所示:

圖中組件共分爲四個部分:

  1. Nginx Ingress Controller 是應用網關的核心組件。KubeSphere 項目網關基於 Nginx Ingress Controller 實現,它通過獲 Ingress 對象生成 Nginx 反向代理規則配置並配置應用於 Nginx 服務。應用路由是一個 Ingress 對象。應用網關依賴於 Service 對外暴露 Nginx 服務,因此 Service 在生產環境中一般設置爲 LoadBalancer 類型,由雲服務商配置其公有云 IP 地址及外部負載均衡器,用以保障服務的高可用性。
  2. 外部負載均衡器,應用網關的 Service 生成的外部負載均衡器,一般由各個雲服務商提供。因此每種負載均衡器的特性有很多差別,比如 SLA、帶寬、IP 配置等等。我們一般可以通過服務商提供的註解對其進行配置,在設置網關時,我們通常需要了解這些特性。
  3. DNS 域名解析服務, 一般由域名服務商提供服務,我們可以配置域名解析紀錄將域名指向 LoadBalancer 的公網 IP。如果子域名也指向同一 IP,我們可以可使用泛域名解析方式。
  4. 用戶服務與應用路由,用戶需要爲應用程序創建 Service 用於暴露集羣內的服務,然後創建應用路由對外暴露服務。注,Nginx Ingress Controller 並不通過 Kube-proxy 訪問服務 IP。它通過服務查找與之關聯 PODEndPoint,並將其設置爲 NginxUpstream。Nginx 直接連接 POD 可以避免由 Service 帶來的額外網絡開銷。

應用路由 vs Service(type=LoadBalancer)

在實踐過程中,應用路由與 Service 的應用場景常常令人混淆。它們都可以向集羣外暴露集羣內服務,並提供負載均衡功能。並且應用路由看起來也是依賴於服務的,那麼他們究竟有何區別呢?這個問題我們需要從以下幾個角度理解。

  1. Service 最初的設計動機是將某個服務的後端(Pod)進行抽象並公開爲網絡服務。它通常是以一個服務爲單位的,所有後端均運行相同的服務端。而應用路由的設計目標是對 API 對象進行管理。它雖然也可以暴露一個服務,但是它更強大的功能在於其可以將一系列服務進行聚合,對外提供統一的訪問 IP、域名、URL 等。
  2. Service 工作在 TCP/IP 協議的第四層,因此它使用 IP+端口+協議 三元組作爲服務的唯一標識。因此當我們需要暴露一個服務時,它不能與其他已存在的服務衝突。例如,我們暴露基於 HTTP/HTTPs 的服務時,通常這類服務都會佔用 80、443 端口,爲了避免端口衝突,就需要爲每個暴露的服務申請一個獨立的 IP 地址,導致資源浪費。應用路由工作在七層,所有通過應用路由暴露的服務都可以共享項目網關的 IP 地址和 80、443 端口。每個應用路由使用 Host+URL 作爲服務的唯一標識,將 HTTP 請求轉發到後端服務中。
  3. Service 支持 TCP 與 UDP 協議並且對上層協議沒有限制,而應用路由目前只支持 HTTP/HTTPs 或 HTTP2 協議,無法轉發基於 TCP 或 UDP 的其他協議。

結合以上三點,我們不難得看出:應用路由更適用於使用 HTTP 協議的微服務架構的場景中,而 Service 雖然對 HTTP 協議沒有深度的支持,但是它可以支持更多其他協議。

應用路由 vs Spring Cloud Gateway 或 Ocelot

Java、.net Core 的開發人員對 Spring Cloud GatewayOcelot 一定不會感到陌生,他們是各自語言領域中最常用的 API 網關。那麼到我們是否可以直接使用這些網關呢?理解這個問題,我們首先要知道什麼是 API 網關,在 Wiki 百科中 API Gateway 並沒有一個明確的定義,但我們從各個大廠的服務說明中可以得出一個基本的結論:

API 網關作爲用戶與後端服務之間的唯一入口管理後端服務,即 API 網關提供了一個方向代理服務將後端服務進行聚合,將客戶端請求路由到後端服務並將結果返回給客戶端。同時,API 網關可提供身份認證、監控、負載均衡、HTTPS offloading 等高級功能。

因此,應用路由承擔了 API 網關的職責,即它與 Spring Cloud GatewayOcelot 等 API 網關具有同等地位。諸如 Spring Cloud Gateway 類的 API 網關通過 Service 的方式暴露到集羣外部也可替代部分應用路由功能。我們接下做一個簡要的對比,並分析一下他們的優缺點:

  1. 作爲應用網關的基本職責,它們均具有路由轉發功能。並且以上提到的網關均支持基於 HOST、URL 的路由轉發規則設置。
  2. 服務註冊與發現,Spring Cloud Gateway 等全家桶式解決方案提供了非常豐富的支持選項,對於 java 開發者更爲友好,網關上的服務均可通過註冊中心服務無縫銜接。而 Ocelot 雖然未內置服務發現與註冊方案,但是可以通過 Ocelot + Consul 的方式實現。對比之下 Kubernetes 集羣中部署應用,一般採用基於 DNS 的服務發現方式,但並沒有爲客戶端提供一個統一的服務註冊發現方式。對外暴露的服務需要顯示的創建 Ingress 規則。相比之下 Spring Cloud Gateway 類的 API 網關使用相同技術棧,這可以極大的簡化開發人員的學習成本。
  3. 通用性上,Ingress 是雲原生背景下 Kubernetes 社區定義的 API 管理規範。KubeSphere 默認採用 Nginx Ingress Controller實現。同時我們可以使用任何兼容的第三方 Ingress 控制器進行替換。Ingress 中只定義了基本共性的功能,但網關通常會提供日誌、監控、安全等更多通用的運維工具。相比之下,與語言緊密結合的 API 網關通常與開發平臺進行綁定,語言相互替代性較差(不願引入更多技術棧或無客戶端集成支持)。功能相對固定,但大多提供了良好的插件機制,開發人員使用自己熟悉的語言進行拓展。
  4. 性能方面,毋庸置疑,以基於 Nginx 的 Ingress Controller 爲代表的通用型 API 網關,比 Spring Cloud GatewayOcelot 等有非常明顯的性能優勢。

總體來講,每種網關都有其優缺點或侷限性。在項目初期應首先考慮應用網關的架構。在基於雲原生的場景下,應用路由會是一個不錯的選擇。而如果您的團隊依賴於開發技術棧,那麼常用技術棧中的 API 網關通常也會作爲首選。但這並不意味着它們必須進行二選一,在一些複雜場景下我們可以結合二者的優勢,開發人員使用自己熟知的 API 網關用於服務聚合、認證鑑權等功能,同時在其前方放置應用網關實現日誌監控,負載均衡,HTTPs offloading 等工作。

微軟官方微服務架構示例 eShopOnContainers 即採用了該種混合架構。

動手實戰

理解以上應用場景和整體架構後,我們接下來演示如何在 KubeSphere 中配置項目網關和應用路由。以下內容將基於 Weaveworks 的微服務演示項目 SockShop 實現。SockShop 是一個典型的前後端分離架構,它由前端服務 front-end 和若干後端服務 cataloguecartsorders 等組成。在當前架構下,front-end 除了承擔靜態頁面服務的功能,還承擔了後端 API 代理轉發的任務。我們假設以下場景,即由 Nodejs 轉發 API 造成服務異步阻塞,從而影響頁面性能。因此我們決定使用 ingress 直接轉發服務 catalogue 用以提升性能。下面我們看一下詳細配置步驟。

準備工作

  1. 在部署 SockShop 之前,我們首先要配置一個用於演示的企業空間 workspace-demo 和項目 sock-shop。具體步驟請參考《創建企業空間、項目、帳戶和角色》
  1. 完成項目 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工作負載頁面查看部署的狀態,等待所有的部署都正常運行後,我們再進行下一步操作。

項目網關配置

  1. 進入 sock-shop 項目,從左側導航欄進入項目設置下的高級設置頁面,然後點擊設置網關。

  2. 在接下來彈出的對話框中,需要根據 KubeSphere 的安裝環境進行設置。如果您使用的是本地開發環境或私有環境可以選擇 NodePort 的方式暴露網關。如果是託管 Kubernetes 雲服務,一般選擇 LoadBalancer。

應用路由配置

  1. 首先,我們選擇左側導航欄應用負載中的應用路由,點擊右側的創建。在基本信息中填寫名稱 frontend。在路由規則中,添加一條新的規則。由於是演示項目,我們使用自動生成模式。KubeSphere 自動以<服務名稱>.<項目名稱>.<網關地址>.nip.io 格式生成域名,該域名由 nip.io 自動解析爲網關地址。在路徑、服務、端口上依次選擇 "/"、"front-end"、"80"。點擊下一步後,繼續點擊創建

  1. 路由創建完成後,可以在應用路由列表頁面點擊 frontend 進入詳情。並在規則中可以點擊點擊訪問訪問按鈕。在新的瀏覽器 tab 下,應該出現如下的網站:

  1. 爲了與下面的步驟進行對比,我們在 SockShop 的網站頁面打開調試功能查看網絡請求,以 Chrome 爲例只需點擊鍵盤的F12鍵。刷新一下頁面後我們找到如下 catalogue API 請求:

該請求頭中的 X-Powered-By:Express 表明了這條請求是由前端的 Nodejs 應用轉發。

  1. 接下來,在 frontend 的詳情頁面點擊左側的更多操作,並選擇編輯規則。在彈出的編輯規則頁面,選擇剛剛增加的規則,並點擊左側的編輯圖標。新增一條路徑,在路徑、服務、端口上依次選擇"/catalogue"、"catalogue"、"80"。保存該設置。編輯後的規則如下:

  1. 我們再次訪問 SockShop 的網站頁面,該頁面並沒有任何變化。我們使用瀏覽器調試器,再次查看網絡請求,catalogue 的請求如下:

我們發現該請求已經沒有了 X-Powered-By:Express 請求頭,這說明了我們上面應用的規則已經生效,catalogue相關的 API 請求已經通過應用路由直接轉發 catalogue 服務了,而不需要再通過 fron-tend 服務進行中轉。以上的配置我們利用了路由規則的最長匹配規則。“/catalogue”比更路徑具有更高的優先級。

更多配置內容可以參考《應用路由》

總結

本篇內容簡述了應用路由的基本架構,並與 Kubernetes Service 及其他應用網關分別做了對比。最後通過 SockShop 這個案例講解的應用路由的配置方法。希望讀者對應用路由能有進一步的理解,根據應用的特性選擇合適的外部服務暴露方式。

本文由博客一文多發平臺 OpenWrite 發佈!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章