kubernetes實踐之七十一:Istio之流量管理(下)

百聯達發表於2018-08-14

一:簡介

Istio 提供了一個簡單的配置模型,用來控制 API 呼叫以及應用部署內多個服務之間的四層通訊。運維人員可以使用這個模型來配置服務級別的屬性,這些屬性可以是斷路器、超時、重試,以及一些普通的持續釋出任務,例如金絲雀釋出、A/B 測試、使用百分比對流量進行控制,從而完成應用的逐步釋出等。

例如,將 reviews 服務 100% 的傳入流量傳送到 v1 版本,這一需求可以用下面的規則來實現:

apiVersion: networking.istio.io/v1alpha3
    kind: VirtualServicemetadata:
  name: reviewsspec:
  hosts:
  - reviews  http:
  - route:
    - destination:
        host: reviews        
        subset: v1

這個配置的用意是,傳送到 reviews 服務(在 host 欄位中標識)的流量應該被路由到 reviews 服務例項的 v1 子集中。路由中的 subset 制定了一個預定義的子集名稱,子集的定義來自於目標規則配置

apiVersion: networking.istio.io/v1alpha3
      kind: DestinationRulemetadata:
      name: reviewsspec:
      host: reviews  
      subsets:
      - name: v1    
      labels:
      version: v1  
      - name: v2    
      labels:
      version: v2

子集中會指定一或多個標籤,用這些標籤來區分不同版本的例項。假設在 Kubernetes 上的 Istio 服務網格之中有一個服務,version: v1 代表只有標籤中包含 “version:v1” 的 Pod 才會收到流量。

規則可以使用 istioctl 客戶端工具 進行配置,如果是 Kubernetes 部署,還可以使用 kubectl 命令完成同樣任務,但是隻有 istioctl 會在這個過程中對模型進行檢查,所以我們推薦使用 istioctl。在配置請求路由任務中包含有配置示例。

Istio 中包含有四種流量管理配置資源,分別是 VirtualService、DestinationRule、ServiceEntry、以及 Gateway。下面會講一下這幾個資源的一些重點。在網路參考中可以獲得更多這方面的資訊。

二:Virtual Services

Virtual Services在Istio服務網格中定義了對服務的請求如何進行路由控制。例如一個 Virtual Service 可以把請求路由到不同版本,甚至是可以路由到一個完全不同於請求要求的服務上去。路由可以用很多條件進行判斷,例如請求的源和目的、HTTP 路徑和 Header 以及各個服務版本的權重等。

  1. 路由規則定義

    路由規則對應著一或多個用 VirtualService 配置指定的請求目的主機。這些主機可以是、也可以不是實際的目標負載,甚至可以不是一個網格內可路由的服務。例如要給到 reviews 服務的請求定義路由規則,可以使用內部的名稱 reviews,也可以用域名 bookinfo.com,VirtualService 可以這樣使用 host 欄位:

    hosts:

     - reviews

      - bookinfo.com

    host 欄位用顯示或者隱式的方式定義了一或多個完全限定名(FQDN)。上面的 reviews,會隱式的擴充套件成為特定的 FQDN,例如在 Kubernetes 環境中,全名會從 VirtualService 所在的叢集和名稱空間中繼承而來(比如說 reviews.default.svc.cluster.local)

 2.根據來源或 Header 制定規則

a. 根據特定使用者進行限定。 例如,可以制定一個規則,只對來自 reviews 服務的 Pod 生效

apiVersion: networking.istio.io/v1alpha3
  kind: VirtualServicemetadata:
  name: ratingsspec:
  hosts:
  - ratings  
  http:
  - match:
      sourceLabels:
        app: reviews    ...

sourceLabels 的值依賴於服務的實現。比如說在 Kubernetes 中,跟服務的 Pod 選擇標籤一致。

b. 根據呼叫方的特定版本進行限定。 例如下面的規則對前一個例子進行修改,reviews 服務的 v2 版本發出的請求才會生效:

apiVersion: networking.istio.io/v1alpha3
  kind: VirtualServicemetadata:
  name: ratingsspec:
  hosts:
  - ratings  
  http:
  - match:
    - sourceLabels:
        app: reviews        
        version: v2    ...

c. 根據 HTTP Header 選擇規則。 下面的規則只會對包含了 end-user 頭,且值為 jason 的請求生效:

apiVersion: networking.istio.io/v1alpha3
  kind: VirtualServicemetadata:
  name: reviewsspec:
  hosts:
    - reviews  
  http:
  - match:
    - headers:
        end-user:
          exact: jason    ...

3.在服務之間分拆流量

每個路由規則都需要對一或多個有權重的後端進行甄別並呼叫合適的後端。每個後端都對應一個特定版本的目標服務,服務的版本是依靠標籤來區分的。如果一個服務版本包含多個註冊例項,那麼會根據為該服務定義的負載均衡策略進行路由,預設策略是 round-robin。

例如下面的規則會把 25% 的 reviews 服務流量分配給 v2 標籤;其餘的 75% 流量分配給 v1:

apiVersion: networking.istio.io/v1alpha3
  kind: VirtualServicemetadata:
  name: reviewsspec:
  hosts:
    - reviews  
  http:
  - route:
    - destination:
        host: reviews        
        subset: v1      
        weight: 75
    - destination:
        host: reviews        
        subset: v2      
        weight: 25

4.超時和重試

預設情況下,HTTP 請求的超時設定為 15 秒,可以使用路由規則來覆蓋這個限制:

apiVersion: networking.istio.io/v1alpha3
  kind: VirtualServicemetadata:
  name: ratingsspec:
  hosts:
    - ratings  
  http:
  - route:
    - destination:
        host: ratings        
        subset: v1    
        timeout: 10s

5.在請求中進行錯誤注入


在根據路由規則向選中目標轉發 http 請求的時候,可以向其中注入一或多個錯誤。錯誤可以是延遲,也可以是退出。

下面的例子在目標為 ratings:v1 服務的流量中,對其中的 10% 注入 5 秒鐘的延遲。

apiVersion: networking.istio.io/v1alpha3
  kind: VirtualServicemetadata:
  name: ratingsspec:
  hosts:
  - ratings  
  http:
  - fault:
      delay:
        percent: 10
        fixedDelay: 5s    
  route:
    - destination:
        host: ratings        
        subset: v1


三:DestinationRule

1.目標規則

在請求被 VirtualService 路由之後,DestinationRule 配置的一系列策略就生效了。這些策略包含斷路器、負載均衡以及 TLS 等的配置內容。DestinationRule 還定義了對應目標主機的可路由 subset(例如有命名的版本)。VirtualService 在向特定服務版本傳送請求時會用到這些子集。

apiVersion: networking.istio.io/v1alpha3
  kind: DestinationRulemetadata:
  name: reviewsspec:
  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

2.斷路器

可以用一系列的標準,例如連線數和請求數限制來定義簡單的斷路器。

例如下面的 DestinationRule 給 reviews 服務的 v1 版本設定了 100 連線的限制:

apiVersion: networking.istio.io/v1alpha3
  kind: DestinationRulemetadata:
  name: reviewsspec:
  host: reviews  
  subsets:
  - name: v1    
  labels:
      version: v1    
  trafficPolicy:
      connectionPool:
        tcp:
          maxConnections: 100

3.目標規則的評估

和路由規則類似,這些策略也是和特定的 host 相關聯的,如果指定了 subset,那麼具體生效的 subset 的決策是由路由規則來決定的。

規則評估的第一步,是確認 VirtualService 中所請求的主機相對應的路由規則(如果有的話),這一步驟決定了將請求發往目標服務的哪一個 subset(就是特定版本)。下一步,被選中的 subset 如果定義了策略,就會開始是否生效的評估。

這一演算法需要留心是,為特定 subset 定義的策略,只有在該 subset 被顯式的路由時候才能生效。例如下面的配置,只為 review 服務定義了規則(沒有對應的 VirtualService 路由規則)。

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRulemetadata:
  name: reviewsspec:
  host: reviews  
subsets:
  - name: v1    
labels:
      version: v1    
trafficPolicy:
      connectionPool:
        tcp:
         maxConnections: 100

既然沒有為 reviews 服務定義路由規則,那麼就會使用預設的 round-robin 策略,偶爾會請求到 v1 例項,如果只有一個 v1 例項,那麼所有請求都會傳送給它。然而上面的策略是永遠不會生效的,這是因為,預設路由是在更底層完成的任務,策略引擎無法獲知最終目的,也無法為請求選擇匹配的 subset 策略。


有兩種方法來解決這個問題。可以把路由策略提高一級,要求他對所有版本生效:

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRulemetadata:
  name: reviewsspec:
  host: reviews  
trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 100
  subsets:
  - name: v1    
  labels:
      version: v1

還有一個更好的方法,就是為服務定義路由規則,例如給 reviews:v1 加入一個簡單的路由規則:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualServicemetadata:
  name: reviewsspec:
  hosts:
  - reviews  
http:
  - route:
    - destination:
        host: reviews        
        subset: v1

雖然 Istio 在沒有定義任何規則的情況下,能將所有來源的流量傳送給所有版本的目標服務。然而一旦需要對版本有所區別,就需要制定規則了。從一開始就給每個服務設定預設規則,是 Istio 世界裡推薦的最佳實踐。

四:Service Entries

Istio 內部會維護一個服務登錄檔,可以用 ServiceEntry 向其中加入額外的條目。通常這個物件用來啟用對 Istio 服務網格之外的服務發出請求。例如下面的 ServiceEntry 可以用來允許外部對 *.foo.com 域名上的服務主機的呼叫。

apiVersion: networking.istio.io/v1alpha3
  kind: ServiceEntrymetadata:
  name: foo-ext-svcspec:
  hosts:
  - *.foo.com  
    ports:
  - number: 80
    name: http    
    protocol: HTTP  
    - number: 443
    name: https    
    protocol: HTTPS

五:Gateway

Gateway 為 HTTP/TCP 流量配置了一個負載均衡,多數情況下在網格邊緣進行操作,用於啟用一個服務的 Ingress 流量。

和 Kubernetes Ingress 不同,Istio Gateway 只配置四層到六層的功能(例如開放埠或者 TLS 配置)。繫結一個 VirtualService 到 Gateway 上,使用者就可以使用標準的 Istio 規則來控制進入的 HTTP 和 TCP 流量。

例如下面提供一個簡單的 Gateway 程式碼,配合一個負載均衡,允許外部針對主機 bookinfo.com 的 https 流量:

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

要為 Gateway 配置對應的路由,必須為定義一個同樣 host 定義的 VirtualService,其中用 gateways 欄位來繫結到定義好的 Gateway 上:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualServicemetadata:
  name: bookinfospec:
  hosts:
    - bookinfo.com  gateways:
  - bookinfo-gateway # <---- 繫結到 Gateway
  http:
  - match:
    - uri:
        prefix: /reviews    
route:
    ...

雖然主要用於管理 Ingress 流量,Gateway 還可以用在純粹的內部服務之間或者 egress 場景下使用。不管處於什麼位置,所有的閘道器都可以以同樣的方式進行配置和控制。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/28624388/viewspace-2200052/,如需轉載,請註明出處,否則將追究法律責任。

相關文章