了解流量路由

Istio 的目標之一是充當「透明代理」,可以將其放入現有的叢集中,讓流量像以前一樣繼續流動。然而,由於額外的功能(例如請求負載平衡),Istio 可以使用與典型 Kubernetes 叢集不同的強大方式管理流量。為了了解您的網格中發生的情況,了解 Istio 如何路由流量非常重要。

前端和後端

在 Istio 中的流量路由中,有兩個主要階段

  • 「前端」是指我們如何匹配正在處理的流量類型。這是識別要將流量路由到哪個後端以及要套用哪些策略所必需的。例如,我們可能會讀取 http.ns.svc.cluster.localHost 標頭,並識別請求是針對 http 服務的。有關此比對如何運作的更多資訊,請見下文。
  • 「後端」是指我們在比對流量後將流量發送到的位置。使用上面的範例,在識別請求的目標是 http 服務後,我們會將其發送到該服務中的端點。然而,這種選擇並非總是如此簡單;Istio 允許透過 VirtualService 路由規則自訂此邏輯。

標準 Kubernetes 網路也有相同的概念,但它們更簡單且通常是隱藏的。當建立 Service 時,通常會有一個相關的前端 - 自動建立的 DNS 名稱(例如 http.ns.svc.cluster.local)和一個自動建立的 IP 位址來表示服務(ClusterIP)。同樣,也會建立後端 - EndpointsEndpointSlice - 它表示服務選擇的所有 Pod。

協定

與 Kubernetes 不同,Istio 能夠處理應用程式層級的協定,例如 HTTP 和 TLS。這使得前端的匹配方式與 Kubernetes 中可用的方式有所不同。前端

一般而言,Istio 理解三種協定類別

  • HTTP,包括 HTTP/1.1、HTTP/2 和 gRPC。請注意,這不包括 TLS 加密流量 (HTTPS)。
  • TLS,包括 HTTPS。
  • 原始 TCP 位元組。

協定選擇文件說明了 Istio 如何決定使用哪種協定。

「TCP」的使用可能會讓人感到困惑,因為在其他情況下,它會被用來區分其他 L4 協定,例如 UDP。在 Istio 中提到 TCP 協定時,通常表示我們將其視為原始位元組串流,而不剖析應用程式層級的協定,例如 TLS 或 HTTP。

流量路由

當 Envoy 代理收到請求時,它必須決定將請求轉發到何處(如果有的話)。預設情況下,這會轉發到最初請求的服務,除非進行了自訂。其運作方式取決於所使用的協定。

TCP

當處理 TCP 流量時,Istio 只有非常少量的可用資訊來路由連線 - 只有目標 IP 和 Port。這些屬性用於判斷目標服務;代理程式設定為監聽每個服務 IP (<Kubernetes ClusterIP>:<Port>) 對,並將流量轉發到上游服務。

對於自訂,可以設定 TCP VirtualService,允許比對特定 IP 和埠,並將其路由到與請求不同的上游服務。

TLS

當處理 TLS 流量時,Istio 比原始 TCP 可用更多資訊:我們可以檢查 TLS 交握期間呈現的 SNI 欄位。

對於標準服務,使用與原始 TCP 相同的 IP:Port 比對。但是,對於沒有定義服務 IP 的服務,例如ExternalName 服務,SNI 欄位將用於路由。

此外,可以使用 TLS VirtualService 設定自訂路由,以比對 SNI,並將請求路由到自訂目的地。

HTTP

HTTP 允許比 TCP 和 TLS 更豐富的路由。使用 HTTP,您可以路由個別 HTTP 請求,而不僅僅是連線。此外,還有許多豐富的屬性可用,例如主機、路徑、標頭、查詢參數等。

雖然 TCP 和 TLS 流量在有無 Istio 的情況下通常行為相同(假設沒有應用任何組態來自訂路由),但 HTTP 有顯著差異。

  • Istio 將對個別請求進行負載平衡。一般來說,這是非常理想的,尤其是在具有長時間連線的場景中,例如 gRPC 和 HTTP/2,其中連線層級負載平衡效果不佳。
  • 請求會根據埠和 Host 標頭進行路由,而不是埠和 IP。這表示目標 IP 位址實際上會被忽略。例如,curl 8.8.8.8 -H "Host: productpage.default.svc.cluster.local" 將會被路由到 productpage 服務。

不匹配的流量

如果無法使用上述方法之一比對流量,則會將其視為直通流量。預設情況下,這些請求將會按原樣轉發,這可確保 Istio 不知道的服務(例如沒有建立 ServiceEntry 的外部服務)的流量繼續正常運作。請注意,當轉發這些請求時,將不會使用相互 TLS,且遙測收集會受到限制。

服務類型

除了標準的 ClusterIP 服務之外,Istio 還支援全系列的 Kubernetes 服務,但有一些注意事項。

LoadBalancerNodePort 服務

這些服務是 ClusterIP 服務的超集,主要用於允許外部用戶端存取。這些服務類型受到支援,其行為與標準的 ClusterIP 服務完全相同。

無頭服務

無頭服務是一種沒有指定 ClusterIP 的服務。相反地,DNS 回應將包含每個端點 (即 Pod IP) 的 IP 位址,而該端點是服務的一部分。

一般來說,Istio 不會為每個 Pod IP 設定監聽器,因為它在服務層級運作。但是,為了支援無頭服務,會為無頭服務中的每個 IP:Port 對設定監聽器。例外情況是宣告為 HTTP 的協定,它會比對 Host 標頭的流量。

ExternalName 服務

ExternalName 服務本質上只是一個 DNS 別名。

為了使事情更具體,請考慮以下範例

apiVersion: v1
kind: Service
metadata:
  name: alias
spec:
  type: ExternalName
  externalName: concrete.example.com

由於沒有 ClusterIP 或 Pod IP 可以比對,因此對於 TCP 流量,Istio 中的流量比對完全沒有任何變更。當 Istio 收到請求時,它們會看到 concrete.example.com 的 IP。如果這是 Istio 知道的服務,則會如上述說明路由。否則,會將其視為無法比對的流量處理

對於 HTTP 和 TLS(比對主機名稱),情況會略有不同。如果目標服務 (concrete.example.com) 是 Istio 知道的服務,則別名主機名稱 (alias.default.svc.cluster.local) 將會作為TLSHTTP 比對的額外比對項目新增。否則,將不會有任何變更,因此會將其視為無法比對的流量處理。

ExternalName 服務永遠不能單獨作為後端。相反地,它只會用作現有服務的額外前端比對。如果明確將其用作後端,例如在 VirtualService 目的地中,則相同的別名會適用。也就是說,如果將 alias.default.svc.cluster.local 設定為目的地,則請求將會傳送到 concrete.example.com。如果 Istio 不知道該主機名稱,則請求會失敗;在這種情況下,為 concrete.example.com 提供 ServiceEntry 會使此組態運作。

ServiceEntry

除了 Kubernetes 服務之外,還可以建立服務項目,以擴充 Istio 已知的服務集。這對於確保傳送到外部服務(例如 example.com)的流量獲得 Istio 的功能非常有用。

設定 addresses 的 ServiceEntry 會執行與 ClusterIP 服務類似的路由。

但是,對於沒有任何 addresses 的服務項目,將會比對埠上的所有 IP。這可能會阻止在相同埠上的無法比對的流量被正確轉發。因此,最好盡可能避免這些情況,或在需要時使用專用埠。HTTP 和 TLS 沒有此限制,因為路由是根據主機名稱/SNI 完成的。

這個資訊對您有幫助嗎?
您是否有任何改進建議?

感謝您的意見反應!