Blog:部落格園 個人
參考:Ingress | Kubernetes、《Kubernetes進階實戰》
Contour是Kubernetes Ingress控制器的另一款開源實現,它以高效能的Envoy代理程式作為資料平面,支援開箱即用的動態配置和多種高階路由機制,支援TCP代理,並且提供了自定義資源型別HTTPProxy資源以擴充套件IngressAPI,以更豐富的功能集部分解決了Ingress原始設計中的缺點,是Ingress控制器較為出色的實現之一。
Contour Ingress controller 由兩個元件組成:
Envoy
: 提供高效能反向代理。Contour
: 充當 Envoy 的控制平面,為 Envoy 的路由配置提供統一的來源。
官方文件提供了部署方法:Getting Started with Contour (projectcontour.io)
Envoy
Envoy是專為大型現代SOA架構設計的應用代理和通訊匯流排,使用C++語言編寫,是高效能的HTTP/HTTPS協議代理,支援負載均衡、超時、重試、熔斷、限流和回退等多種高階路由功能,支援HTTP/2和gRPC,而且能夠作為HTTP/1.1和HTTP/2之間的雙向透明代理機制。Envoy原生支援動態配置和服務發現機制,能夠通過xDS API從控制平面(管理伺服器)獲取配置資訊,同時提供了良好的可觀測性,未來甚至會作為UPDA(Universal Data Plane API)的標準實現之一。
作為代理服務,Envoy使用“偵聽器”(listener)維護與下游客戶端的連線,使用叢集管理器管理上游伺服器叢集,並根據偵聽器上配置的代理層級和路由策略“橋接”客戶端與後端伺服器。它支援配置任意數量的偵聽器和任意數量的上游叢集,這些配置可使用靜態方式指定,也可分別基於不同的服務發現API動態生成。
Envoy通過偵聽器監聽網路套接字以接收客戶端請求,並且支援在一個程式上啟用任意數量的偵聽器,從而賦予使用者按需配置Envoy監聽一至多個套接字的能力。每個偵聽器都應獨立配置一些網路(L3/L4)過濾器,在接收到請求後,偵聽器負責例項化指定過濾器鏈中的各個過濾器,並由這些過濾器處理後續的相關事件。一般說來,使用者可根據不同的過濾器鏈配置偵聽器以完成不同代理任務,例如HTTP代理、TCP代理、TLS客戶端認證、限速等。
HTTP是現代面向服務的架構中至關重要的元件,因此Envoy通過名為HTTP連線管理器的網路(L3/L4)過濾器實現HTTP協議的應用層代理,內建支援HTTP/1.1、WebSockets和HTTP/2幾類協議。另外,Envoy在傳輸層和應用層分別提供了對gRPC協議的原生支援,gRPC是來自Google的RPC框架,它基於HTTP/2構建和傳遞請求/響應報文。Envoy內建的HTTP過濾器中的Router負責為HTTP代理實現高階路由功能,包括將DNS域對映到特定的虛擬主機、URL重定向、URL重寫、重試、超時、基於權重或百分比進行流量分發、基於優先順序的路由和基於雜湊策略的路由等。Envoy通過配置的路由資訊生成路由表,並由Router過濾器據此做出路由決策。
每個上游伺服器可由一個稱為端點的邏輯元件進行標識,它代表著此服務監聽的套接字,因此也可直接作為上游服務的識別符號使用。一個叢集可以包含一到多個端點,而一個端點也可隸屬於一到多個叢集。
Envoy的叢集管理器負責管理配置的所有上游叢集,包括獲知上游主機健康可用狀態、負載狀態、連線型別以及適用的上游通訊協議(HTTP/1.1、HTTP/2)等,並向前端的過濾器堆疊暴露API,允許過濾器根據請求及處理結果按需建立與上游叢集的L3/L4或L7的通訊連線。一旦在配置中定義了叢集,叢集管理器需要知道如何解析叢集中的成員,即端點配置資訊。目前,Envoy支援的端點配置支援包括靜態配置、嚴格DNS、邏輯DNS、原始目標和EDS幾種。叢集管理器可通過純靜態的配置資訊載入並初始化叢集,也可通過叢集發現服務(Cluster Discovery Service,CDS)API動態獲取相關的配置,而後一種方式允許將配置資訊儲存在集中式的配置服務中,從而減少重啟Envoy或重新分發配置的次數。
服務發現是面向服務架構的基石。為了更好地適配雲原生環境,Envoy內建了一個層次化的動態配置API用於集中式管理配置資訊,該API可藉助服務發現服務(Service Discovery Service,即服務發現自身作為一種服務)機制支援多種服務發現方式,從而為Envoy提供以下配置資訊的動態發現和更新。
- 端點發現服務(Endpoint Discovery Service,EDS):用於為Envoy動態新增、更新和刪除Service端點,這些端點通常是指上游叢集后端提供特定服務的主機的套接字;EDS事實上是v1時代的SDS(Service Discovery Service)的替代品,而且,SDS在v2版本中專用於指代Secret Discovery Service。
- 叢集發現服務(Cluster Discovery Service,CDS):用於動態新增、更新和刪除Upstream叢集,其中,每個叢集本身都有自己的端點發現(v1版本中的服務發現)機制。
- 路由發現服務(Route Discovery Service,RDS):用於動態新增或更新HTTP路由表。
- 金鑰發現服務(Secret Discovery Service,SDS):傳遞TLS金鑰資訊,從而LDS/ CDS能將主要偵聽器和叢集配置通過金鑰管理系統與金鑰資訊在傳送時相分離。
- 偵聽器發現服務(Listener Discovery Service,LDS):用於動態新增、更新和刪除整個偵聽器,包括其完整的L4或L7過濾器堆疊。
- 健康發現服務(Health Discovery Service,HDS):配置Envoy成為分散式健康狀態檢查網路的成員,負責將健康狀態檢查的相關資訊報告給上級或集中式的健康狀態檢查服務。
- 聚合發現服務(Aggregated Discovery Service,ADS):構建在單個EnvoyAPI提供的資料平面服務之上的多個管理API(例如Istio、Linkerd等);同時操作Envoy API時,使用單個管理伺服器處理單個Envoy的所有更新操作有助於確保Envoy的資料一致性;此API允許所有其他API通過單個管理伺服器的單個gRPC雙向流進行編組,從而實現確定性排序。
- 另外還有ALS(gRPC Access Log Service)、RTDS(Runtime DiscoveryService)、RLS(Rate Limit Service)和CSDS(Client Status DiscoveryService)等,這些API統稱為xDS,相較於v1版本來說,它是一種新的REST-JSON API,其中JSON/YAML格式是基於proto3規範的JSON對映機制派生而來的。另外,xDS API通過gRPC流式傳輸進行更新,該方式有著較低資源需求,因而能降低更新延遲。
HTTPProxy
除了能實現類似於Ingress資源的流量分發等基礎功能,HTTPProxy還封裝了Envoy相當一部分高階路由功能的API,例如基於標頭的路由、流量映象和流量分割等多種高階路由功能,能幫助使用者實現諸如金絲雀部署、藍綠部署和A/B測試等功能。
HTTPProxy支援在單個路由規則中同時指定多個後端服務,預設情況下,所有流量將以等量切分的方式平均分發到多個後端之上,每個後端內部再按照代理伺服器配置的排程演算法進行二級負載均衡。同時,HTTPProxy也允許使用者為每個後端服務使用weight欄位指定一個特定流量百分比,從而將流量以指定的比例在不同的後端服務間進行分發。
基於流量分割的流量切分是完成灰度釋出的常用手段。上線應用的新版本時,無論是出於產品穩定性還是使用者接受程度等因素的考慮,直接以新代舊都充滿風險。因此,灰度釋出是應用程式在生產環境安全上線的一種重要手段,而對於Envoy來說,灰度釋出僅是其流量治理功能的一種典型應用,結合分割策略便能實現常見的金絲雀部署、藍綠部署和A/B測試等應用場景。
事實上,基於標頭的流量分割算是“基於請求內容”灰度部署的一種實現,而流量分割則是“基於流量比例”進行灰度部署的方式。與Kubernetes的Deployment控制器的滾動更新機制相比,HTTPProxy允許使用者按需指定要切分的流量比例,而非按照Pod數量來固定分割的方式。
HTTPProxy中的負載均衡策略是路由規則中的定義,每個路由規則都可以為其後端呼叫的服務按需指定最為合用的負載均衡機制。目前,HTTPProxy暴露了Envoy在叢集上支援的部分排程演算法,主要有如下幾個。
- RoundRobin:按順序輪詢選擇上游端點,此為預設策略。
- WeightedLeastRequest:加權最少連線,但該演算法僅隨機選擇兩個健康的端點,並從中挑選出負載少的端點作為排程目標。
- Random:從後端健康端點中隨機挑選端點。
- Cookie:粘性會話排程機制,把來自某客戶端的所有請求始終排程給同一個後端端點。
工作原理
Contour 同時支援 Ingress
資源物件和 IngressRoute
資源物件(通過 CRD 建立),這些物件都是為進入叢集的請求提供路由規則的集合。這兩個物件的結構和實現方式有所不同,但它們的核心意圖是相同的,都是為進入叢集的請求提供路由規則。如不作特殊說明,後面當我們描述 “Ingress” 時,它將同時適用於 Ingress
和 IngressRoute
物件。
通常情況下,當 Envoy 配置了 CDS
的 endpoint 時,它會定期輪詢端點,然後將返回的 JSON 片段合併到其執行配置中。如果返回到 Envoy 的叢集配置代表當前的 Ingress 物件的集合,則可以將 Contour 視為從 Ingress
物件到 Envoy
叢集配置的轉換器。隨著 Ingress 物件的新增和刪除,Envoy 會動態新增並刪除相關配置,而無需不斷重新載入配置。
在實踐中,將 Ingress 物件轉換為 Envoy 配置更加微妙,需要將 Envoy 中的 xDS 配置(包括 CDS
,EDS
和 RDS
)對映到 Kubernetes 中。Contour 至少需要觀察 Ingress
、Service
和 Endpoint
這幾個資源物件以構建這些服務的響應,它通過 client-go
的 cache/informer 機制免費獲得這些 watchers
。這些 watchers 提供新增,更新和刪除物件的邊緣觸發通知,也可以通過 watch API
在本地快取快取物件,以便後續查詢。
Contour 將收集到的這些物件處理為虛擬主機及其路由規則的有向非迴圈圖(DAG),這表明 Contour 將有權構建路由規則的頂級檢視,並將群集中的相應服務和TLS祕鑰連線在一起。一旦構建了這個新的資料結構,我們就可以輕鬆實現 IngressRoute
物件的驗證,授權和分發。改資料結構匯出的 png
圖片如下圖所示:
Envoy API 呼叫和 Kubernetes API 資源之間的對映關係如下:
- CDS : 叢集發現服務。對映為 Kubernetes 中的
Service
以及一部分 Ingress 物件的TLS
配置。 - EDS : 服務發現服務。對映為 Kubernetes 中的
Endpoint
。Envoy 使用 EDS 自動獲取Cluster
成員,這與 Endpoint 物件中包含的資訊非常匹配。Envoy 使用 Contour 在EDS
響應中返回的名稱查詢EDS
。 - RDS : 路由發現服務。對映為 Kubernetes 中的
Ingress
。提供了虛擬主機名和字首路由資訊的 RDS 與 Ingress 匹配得更好。
總結
基於Kubernetes內建的Ingress釋出服務時,底層使用的是IngressNginx還是Contour控制器並沒有本質上的區別。但Contour提供的CRD資源型別HTTPProxy能夠提供更為完整的路由功能集,大大豐富了Ingress的特性表現。HTTPProxy封裝了Envoy的部分API,從而支援流量切分、流量映象、基於標頭的路由、自定義使用的負載均衡策略、超時和重試、後端端點的健康狀態檢測等高階功能。