了解流量路由
Istio 的目標之一是充當「透明代理」,可以將其放入現有的叢集中,讓流量像以前一樣繼續流動。然而,由於額外的功能(例如請求負載平衡),Istio 可以使用與典型 Kubernetes 叢集不同的強大方式管理流量。為了了解您的網格中發生的情況,了解 Istio 如何路由流量非常重要。
前端和後端
在 Istio 中的流量路由中,有兩個主要階段
- 「前端」是指我們如何匹配正在處理的流量類型。這是識別要將流量路由到哪個後端以及要套用哪些策略所必需的。例如,我們可能會讀取
http.ns.svc.cluster.local
的Host
標頭,並識別請求是針對http
服務的。有關此比對如何運作的更多資訊,請見下文。 - 「後端」是指我們在比對流量後將流量發送到的位置。使用上面的範例,在識別請求的目標是
http
服務後,我們會將其發送到該服務中的端點。然而,這種選擇並非總是如此簡單;Istio 允許透過VirtualService
路由規則自訂此邏輯。
標準 Kubernetes 網路也有相同的概念,但它們更簡單且通常是隱藏的。當建立 Service
時,通常會有一個相關的前端 - 自動建立的 DNS 名稱(例如 http.ns.svc.cluster.local
)和一個自動建立的 IP 位址來表示服務(ClusterIP
)。同樣,也會建立後端 - Endpoints
或 EndpointSlice
- 它表示服務選擇的所有 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 服務,但有一些注意事項。
LoadBalancer
和 NodePort
服務
這些服務是 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
) 將會作為TLS 或 HTTP 比對的額外比對項目新增。否則,將不會有任何變更,因此會將其視為無法比對的流量處理。
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 完成的。