介紹 Istio v1alpha3 路由 API

Istio v1alpha3 路由 API 的介紹、動機和設計原則。

2018 年 4 月 25 日 | 作者:Frank Budinsky - IBM 和 Shriram Rajagopalan - VMware

到目前為止,Istio 提供了一個簡單的 API,透過四個配置資源來管理流量:RouteRuleDestinationPolicyEgressRule 和 (Kubernetes) Ingress。透過這個 API,使用者可以輕鬆管理 Istio 服務網格中的流量。該 API 允許使用者將請求路由到特定版本的服務、注入延遲和故障以進行復原測試、新增逾時和斷路器等等,所有這些都無需更改應用程式碼本身。

儘管此功能已被證明是 Istio 非常引人注目的部分,但使用者回饋也顯示此 API 的確有一些缺點,特別是在使用它來管理包含數千個服務的非常大型的應用程式,以及在處理 HTTP 以外的協定時。此外,使用 Kubernetes Ingress 資源來配置外部流量已被證明嚴重不足以滿足我們的需求。

為了解決這些以及其他問題,正在引入一個新的流量管理 API,也就是 v1alpha3,它將完全取代先前的 API。儘管 v1alpha3 模型在根本上是相同的,但它不向後相容,需要從舊 API 手動轉換。

為了證明這種中斷的合理性,v1alpha3 API 已經過漫長而艱苦的社群審查過程,希望這能產生一個大大改進的 API,經得起時間的考驗。在本文中,我們將介紹新的配置模型,並嘗試解釋影響它的一些動機和設計原則。

設計原則

一些關鍵的設計原則在路由模型的重新設計中發揮了作用

v1alpha3 中的配置資源

典型的網格將具有一個或多個負載平衡器(我們稱之為閘道),它們終止來自外部網路的 TLS,並允許流量進入網格。然後,流量透過 sidecar 閘道在內部服務之間流動。應用程式也經常使用外部服務(例如,Google Maps API)。這些可以直接呼叫,或者在某些部署中,所有離開網格的流量都可能被強制通過專用的輸出閘道。下圖描述了這種思維模型。

Role of gateways in the mesh
Istio 服務網格中的閘道

考慮到上述設定,v1alpha3 引入了以下新的配置資源,以控制流量路由到網格、在網格內以及從網格輸出。

  1. 閘道 (Gateway)
  2. 虛擬服務 (VirtualService)
  3. 目標規則 (DestinationRule)
  4. 服務條目 (ServiceEntry)

VirtualServiceDestinationRuleServiceEntry 分別取代了 RouteRuleDestinationPolicyEgressRuleGateway 是一個與平台無關的抽象概念,用於為流向專用中間盒的流量建模。

下圖描述了跨配置資源的控制流程。

Relationship between different v1alpha3 elements
不同 v1alpha3 元素之間的關係

閘道 (Gateway)

Gateway 為 HTTP/TCP 流量配置負載平衡器,無論它將在哪裡執行。網格內可以存在任意數量的閘道,並且可以同時存在多個不同的閘道實作。事實上,閘道配置可以透過將工作負載 (pod) 標籤集指定為配置的一部分來繫結到特定的工作負載,從而允許使用者透過編寫簡單的閘道控制器來重複使用現成的網路設備。

對於輸入流量管理,您可能會問:為什麼不重複使用 Kubernetes Ingress API?事實證明,Ingress API 無法表達 Istio 的路由需求。透過嘗試在不同的 HTTP 代理之間找到一個共同的點,Ingress 只能支援最基本的 HTTP 路由,並最終將現代代理的其他所有功能推入不可移植的註解中。

Istio Gateway 透過將 L4-L6 規範與 L7 分離來克服 Ingress 的缺點。它僅配置所有優良 L7 代理統一實作的 L4-L6 功能(例如,要公開的埠、TLS 配置)。然後,使用者可以使用標準的 Istio 規則,透過將 VirtualService 繫結到它,來控制進入 Gateway 的 HTTP 請求和 TCP 流量。

例如,以下簡單的 Gateway 配置了一個負載平衡器,以允許主機 bookinfo.com 的外部 https 流量進入網格

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: bookinfo-gateway
spec:
  servers:
  - port:
      number: 443
      name: https
      protocol: HTTPS
    hosts:
    - bookinfo.com
    tls:
      mode: SIMPLE
      serverCertificate: /tmp/tls.crt
      privateKey: /tmp/tls.key

要配置相應的路由,必須為相同的主機定義 VirtualService(在以下章節中描述),並使用配置中的 gateways 欄位將其繫結到 Gateway

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: bookinfo
spec:
  hosts:
    - bookinfo.com
  gateways:
  - bookinfo-gateway # <---- bind to gateway
  http:
  - match:
    - uri:
        prefix: /reviews
    route:
    ...

Gateway 可以用於為邊緣代理或純內部代理建模,如第一個圖所示。無論位置如何,所有閘道都可以以相同的方式配置和控制。

虛擬服務 (VirtualService)

用稱為「虛擬服務」的東西取代路由規則,起初可能看起來很奇怪,但實際上它在根本上是一個更好的名稱,特別是在重新設計 API 以解決先前模型的可擴展性問題之後。

實際上,已更改的是,我們現在配置(虛擬)目標本身,其所有規則都位於相應的 VirtualService 資源的有序列表中,而不是使用一組針對特定目標服務的個別配置資源(規則)來配置路由,每個配置資源都包含一個優先順序欄位來控制評估順序。例如,在先前我們有兩個 Bookinfo 應用程式的 reviews 服務的 RouteRule 資源,如下所示

apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
  name: reviews-default
spec:
  destination:
    name: reviews
  precedence: 1
  route:
  - labels:
      version: v1
---
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
  name: reviews-test-v2
spec:
  destination:
    name: reviews
  precedence: 2
  match:
    request:
      headers:
        cookie:
          regex: "^(.*?;)?(user=jason)(;.*)?$"
  route:
  - labels:
      version: v2

v1alpha3 中,我們在單個 VirtualService 資源中提供相同的配置

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
    - reviews
  http:
  - match:
    - headers:
        cookie:
          regex: "^(.*?;)?(user=jason)(;.*)?$"
    route:
    - destination:
        host: reviews
        subset: v2
  - route:
    - destination:
        host: reviews
        subset: v1

如您所見,reviews 服務的所有規則都整合在一個地方,這起初可能看起來不那麼好。但是,如果您仔細觀察這個新模型,您會發現存在根本的差異,這些差異使 v1alpha3 的功能強大得多。

首先,請注意,VirtualService 的目標服務是使用 hosts 欄位(事實上是重複欄位)指定的,然後在每個路由規格的 destination 欄位中再次指定。這與先前的模型有非常重要的差異。

VirtualService 描述了一個或多個使用者可尋址目標與網格內實際目標工作負載之間的對應關係。在我們的範例中,它們是相同的,但是,使用者尋址的主機可以是任何具有可選萬用字元字首或 CIDR 字首的 DNS 名稱,這些名稱將用於尋址服務。這在促進將單體應用程式轉變為由不同的微服務建構的複合服務時,特別有用,而無需服務的消費者適應這種轉變。

例如,以下規則允許使用者將 Bookinfo 應用程式的 reviewsratings 服務視為 http://bookinfo.com/ 上更大的(虛擬)服務的一部分來尋址

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: bookinfo
spec:
  hosts:
    - bookinfo.com
  http:
  - match:
    - uri:
        prefix: /reviews
    route:
    - destination:
        host: reviews
  - match:
    - uri:
        prefix: /ratings
    route:
    - destination:
        host: ratings
  ...

VirtualService 的主機實際上不必是服務註冊表的一部分,它們只是虛擬目標。這允許使用者為在網格內沒有可路由條目的虛擬主機的流量建模。可以透過將 VirtualService 繫結到相同主機的 Gateway 配置(如先前章節中所述)將這些主機公開到網格外部。

除了這種根本性的重新結構之外,VirtualService 還包含其他幾個重要的變更

  1. 可以在 VirtualService 配置中表達多個匹配條件,減少對冗餘規則的需求。

  2. 每個服務版本都有一個名稱(稱為服務子集)。屬於子集的 pod/VM 集合在 DestinationRule 中定義,在以下章節中描述。

  3. 可以使用萬用字元 DNS 字首指定 VirtualService 主機,以為所有匹配的服務建立單個規則。例如,在 Kubernetes 中,要為 foo 命名空間中的所有服務應用相同的重寫規則,VirtualService 將使用 *.foo.svc.cluster.local 作為主機。

目標規則 (DestinationRule)

DestinationRule 配置在將流量轉發到服務時要應用的一組策略。它們旨在由服務擁有者編寫,描述斷路器、負載平衡器設定、TLS 設定等。DestinationRule 或多或少與其前身 DestinationPolicy 相同,但有以下例外

  1. DestinationRulehost 可以包含萬用字元字首,允許為許多實際服務指定單個規則。
  2. DestinationRule 定義了相應目標主機的可尋址 subsets(即,具名版本)。這些子集在 VirtualService 路由規格中用於將流量傳送到特定版本的服務。以這種方式命名版本允許我們在不同的虛擬服務中乾淨地引用它們,簡化 Istio 代理發出的統計資訊,並在 SNI 標頭中編碼子集。

為 reviews 服務配置策略和子集的 DestinationRule 可能如下所示

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: reviews
spec:
  host: reviews
  trafficPolicy:
    loadBalancer:
      simple: RANDOM
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
    trafficPolicy:
      loadBalancer:
        simple: ROUND_ROBIN
  - name: v3
    labels:
      version: v3

請注意,與 DestinationPolicy 不同,多個策略(例如,預設和 v2 特有的)在單個 DestinationRule 配置中指定。

服務條目 (ServiceEntry)

ServiceEntry 用於將其他條目新增到 Istio 內部維護的服務註冊表中。它最常用於允許為網格的外部依賴項(例如,從網路使用的 API 或傳送到舊基礎架構中服務的流量)建模。

您先前可以使用 EgressRule 配置的所有內容,都可以輕鬆地使用 ServiceEntry 完成。例如,可以使用如下所示的配置來啟用從網格內部存取簡單的外部服務

apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: foo-ext
spec:
  hosts:
  - foo.com
  ports:
  - number: 80
    name: http
    protocol: HTTP

也就是說,ServiceEntry 比其前身的功能顯著增強。首先,ServiceEntry 不僅限於外部服務配置,它可以有兩種型別:網格內部或網格外部。網格內部條目與所有其他內部服務類似,但用於將服務明確新增到網格中。它們可用於新增服務,作為擴展服務網格以包含非受管基礎架構的一部分(例如,新增到基於 Kubernetes 的服務網格的 VM)。網格外部條目表示網格外部的服務。對於它們,會停用相互 TLS 身份驗證,並且會在用戶端執行策略強制,而不是像往常那樣在內部服務請求的伺服器端執行。

由於 ServiceEntry 設定僅是將一個目的地加入內部服務註冊表中,它可以像註冊表中的任何其他服務一樣,與 VirtualService 和/或 DestinationRule 結合使用。例如,以下 DestinationRule 可用於為外部服務啟動雙向 TLS 連線。

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: foo-ext
spec:
  host: foo.com
  trafficPolicy:
    tls:
      mode: MUTUAL
      clientCertificate: /etc/certs/myclientcert.pem
      privateKey: /etc/certs/client_private_key.pem
      caCertificates: /etc/certs/rootcacerts.pem

除了擴展的通用性之外,ServiceEntry 還提供了幾個優於 EgressRule 的改進,包括以下幾點:

  1. 單個 ServiceEntry 可以配置多個服務端點,而以前需要多個 EgressRules 才能實現。
  2. 現在可以配置端點的解析模式(NONESTATICDNS)。
  3. 此外,我們正在努力解決另一個痛點:需要通過純文本端口訪問安全的外部服務(例如,http://google.com:443)。這應該會在未來幾週內得到修復,允許您直接從您的應用程式訪問 https://google.com。請密切關注 Istio 的修補程式版本 (0.8.x),該版本將解決此限制。

建立和刪除 v1alpha3 路由規則

由於特定目的地的所有路由規則現在都作為有序列表儲存在單個 VirtualService 資源中,因此為特定目的地新增第二個和後續規則不再是透過建立新的 (RouteRule) 資源來完成,而是透過更新該目的地唯一存在的 VirtualService 資源來完成。

舊的路由規則

$ kubectl apply -f my-second-rule-for-destination-abc.yaml

v1alpha3 路由規則

$ kubectl apply -f my-updated-rules-for-destination-abc.yaml

刪除特定目的地的最後一個以外的路由規則,也可以透過使用 kubectl apply 更新現有資源來完成。

當新增或移除引用服務版本的路由時,需要在服務的相應 DestinationRule 中更新 subsets。正如您可能猜到的那樣,這也是使用 kubectl apply 完成的。

總結

Istio v1alpha3 路由 API 的功能比其前身顯著增強,但不幸的是,它不向後相容,需要一次性手動轉換。從 Istio 0.9 開始,將不再支援先前的配置資源,RouteRuleDesintationPolicyEgressRule。Kubernetes 使用者可以繼續使用 Ingress 來為基本路由配置他們的邊緣負載平衡器。但是,進階路由功能(例如,跨兩個版本的流量拆分)將需要使用 Gateway,這是一個功能更強大且強烈推薦的 Ingress 替代品。

致謝

路由模型重新設計和實施工作歸功於以下人員(按字母順序排列)

分享此文章