Istio路由規則配置:VirtualService概念及HTTPRoute講解


VirtualService是Istio流量治理的一個核心配置,可以說是Istio流量治理中最重要、最複雜的規則。所有這裏會兩個篇幅進行講解

1.1 路由規則配置示例

在理解VirtualService的完整功能之前,先看下如下簡單示例:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata: 
  name: forecast
spec:
  hosts:
  - forecast
  http:
  - match:
    - headers:
      location:
        exact: north
    route:
    - destination:
        host: forecast
        subset: v2
   route:
     - destination:
         host: forecast
         subset: v1    

Istio 的配置都是通過Kubernetes 的CRD方式表達的,與傳統的鍵值對配置相比,語法描述性更強。因此,我們很容易理解以上規則的意思:對於forecast 服務訪問,如果在請求的Header中location取值是north,則將請求轉發到服務的v2版本上,其餘請求都轉發到服務的v1版本上。

1.2 路由規則定義

VirtualService 定義了對特定目標服務的一組流量規則。如其名所示,VirtualService在形式上表示一個虛擬服務,將滿足條件的流量都轉發到對應的服務後端,這個服務後端可以是一個服務,也可以是在DestinationRule中定義的服務的子集。
VirtualService 是在Istio V1alpha3版本的API 中引入的信路由定義。不同於V1alpha1 版本中RouteRule使用一組零散的流量規則的組合,並通過優先級表達規則的覆蓋關係,VirtualService 描述了一個具體服務對象,在服務對象內包含了對流量的各種處理,其主體是一個服務而不是一組規則,更易於理解。
VirtualService 中的一些術語如下:

  • Service:服務
  • Service Version: 服務版本
  • Source:發起調用的服務
  • Host:服務調用方連接和調用目標服務時使用的地址,是Istio的幾個配置中非常重要的一個概念,後面會有很多地方用到,值得注意。

通過VirtualService 的配置,應用在訪問目標服務時,只需要指定目標服務的地址即可,不需要額外指定其他目標資源的信息。在實際請求中到底將流量路由到哪種特徵的後端上,則基於在VirtualService中配置的路由規則執行。
VirtualService的完整規則定義很複雜,後面將展開來講。我們先來看看第一級的定義。除了host、gateway 等通用字段,規則的主體是http、tcp和tls,都是複合字段,分別對應HTTPRout、TCPRoute和TLSRoute,表示Istio支持的HTTP、TCP很熱TLS協議的流量規則。

非複合字段hosts和gateway是每種協議都要用到的的公衆字段,體現了VirtualService的設計思想。
1)hosts:是一個重要必選的字段,表示流量發送的目標。可以將其理解爲VirtualService 定義路由規則的的標識,用於匹配訪問地址,可以是一個DNS域名或IP地址。DNS名稱可以使用通配符前綴,也可以只使用短域名,也就是說若不用全限定域名FQDN,則一般的運行平臺會把短域名解析成FQDN。
注意:VirtualService的hosts的短域名解析到完整域名時,補齊的是NamespaceVirtualService的Namespace,而不是Service的Namespace。所以這裏可能會造成一些誤解。建議在規則中最好是寫完整域名,避免由此產生的問題,這樣的問題一般不好定位。
hosts一般建議用字母的域名而不是IP地址,IP地址等多用在以Gateway方式發佈一個服務的場景,這時hosts匹配Gateway的外部訪問地址,當沒有做外部域名解析時,可以是外部的IP地址。

2)gateway:表示應用這些流量規則的Gateway。VirtualService描述的規則則可以用到網格里的Sidecar和入口處的Gateway,表示將路由規則應用於網格內的訪問還是網格外經過Gateway的訪問。其使用方式有點繞,需要注意以下場景
服務只是在網格內訪問的,這是主要的場景。gateway字段可以省略,實際上在VirtualService的定義中都不會出現這個字段。一切都很正常,定義的規則作用於網格內的Sidecar。
服務只是在網格外訪問的。配置要關聯的Gateway,表示對於Gateway進來的流量執行在這個VirtualService上定義的流量規則。
在服務網格內和網格外都需要訪問。這裏要給這個數組字段至少寫兩個元素,一個是外部訪問的Gateway,另一個是保留關鍵字“mesh”。使用中的常見錯誤就是忘了配置“mesh”這個常量而導致錯誤。我們很容易認爲場景3是場景1和場景2的疊加,只需在內部訪問的基礎上添加一個可用於外部訪問的Gateway。
注:在VirtualService中定義的服務需要同時對網格內外部訪問時,gateway字段也要包含兩個元素,一個匹配發布成外部訪問的Gateway名,另外一個是“mesh”這個關鍵字。

3)http:是一個與HTTPRoute類似的路由集合,用於處理HTTP的流量,是Istio中內容最豐富的一種流量規則。

4)tls:是一個TLSRoute類型的路由集合,用於處理非中街的TLS和HTTPS的流量。

5)tcp:是一個TCPRoute類型的路由集合,用於處理TCP流量,應用於所有非HTTP和TLS端口的流量。如果在VirtualService中對HTTPS和TLS沒有定義對於的TLSRoute,則所有流量都會被當成TCP流量來處理,都會走到TCP路由集合上。

  • 注:在VirtualService中的路由規則是一個數組,在應用時匹配到第一個規則生效就跳出,不會檢查後面的規則。

6)exportTo:是Istio 1.1在VirtualService上增加的一個重要字段,用於控制VirtualService跨命名空間的可見性,這樣就可以控制在一個命名空間下定義的VirtualService是否可以被其他命名空間下的Sidecar和Gateway使用了。如果未賦值,則默認全局可見,“.”表示僅應用在當前命名空間,“”表示應用到所有的命名空間。在Istio 1.1 中支持“.”和“”這兩種配置。

1.3 HTTP路由(HTTPRoute)

HTTP是是當前最通用、內容最豐富的協議,控制也最多,是Istio上支持最完整的一種協議。通過它除了可以根據協議的內容進行路由,還可以進行其他的操作。
VirtualService中的http是一個HTTPRoute類型的路由集合,用於處理HTTP的流量。

  • 服務的端口協議是HTTP、HTTP2、GRPC,即在服務的端口名中包含http-、http2-、grpc-等
  • Gateway 的端口協議是HTTP、HTTP2、GRPC,或者Gateway是終結TLS,即Gateway外部是HTTPS,但內部還是HTTP
  • ServiceEntry的端口協議是HTTP、HTTP2、GRPC

1)HTTPRoute規則解析

HTTPRoute規則的功能是:滿足HTTPMatchRequest條件的流量都被路由到HTTPRouteDestination,執行重定向(HTTPRedirect)、重寫(HTTPRewrite)、重試(HTTPRetry)、故障注入(HTTPFaultInjection)、跨站(CorsPolicy)策略等。HTTPRoute不僅可以做路由匹配,還可以做一些寫操作來修改請求本身。

2)HTTP匹配規則(HTTPMatchRequest)

在HTTPRoute中最重要的字段是條件字段Match,爲一個HTTPMatchRequest類型的數組,表示HTTP請求滿足條件,支持將HTTP屬性如uri、scheme、method、authority、port等作爲條件來匹配請求。一個URL的完整格式是:URI=scheme:[//authority]path[?query][#fragment]
authority 的定義與host的定義容易混淆,都是類似於“weather.com”這樣的服務主機名,兩者的差別如下。實際上authority的標準定義是:“authority=[userinfo@]host[:port]”。
看下authority標準定義中的字段:
(1)uri、scheme、method、authority:4個字段都是StringMatch類型,在匹配請求時都支持exact、prefix和regex三種模式的匹配。

(2)headers:匹配請求中的Header,是一個map類型。map的key是字符串類型,value是StringMatch類型。即對於每一個Header的值,都可以使用精確、前綴和正則三種方式進行匹配。如下所示爲自定義Header中source的取值爲“north”,並且ur以“/advertisment" 開頭的請求:

- match:
  - headers:
    source:
      exact: north
    uri:
      prefix: "/advertisment"   

(3)port:表示請求服務的端口。大部分服務只開放一個端口,這也是在微服務中推薦的做法,在這種場景下可以不指定port;

(4)sourceLabels:是一個map類型的鍵值對,表示請求來源負載匹配標籤。這在很多情況有用,可以對一組服務都打一個相同的標籤,然後使用sourceLabels字段對這些服務實施相同的流量規則。在Kubernetes平臺上,這裏的Label就是Pod上的標籤。如下所示表示請求來源是testA服務的v2版本的負載:

http:
- match:    
  - sourceLabels:
      app: testA
      version: v2     

(5)gateway:表示規則應用的Gateway名稱,語義同VirtualService 上面的gateway定義,是一個更細的Match條件,會覆蓋在VirtualService上配置的gateway。

注:在HTTPRoute的匹配條件中,每個HTTPMatchRequest中的諸多屬性是“與”邏輯,幾個元素之間的關係是“或”邏輯。

需要注意的是,在VirtualService中match字段都是數組類型。HTTPMatchRequest中的諸多屬性如uri、header、method等都是“與”邏輯,而數組中幾個元素間關係是“或”邏輯。
在下面的例子中,match包含兩個HTTPMatchRequest元素,其條件的語義是:headers中的source取值爲“north”,且uri以“/advertisment”開頭的請求,或者uri以“/forecast”開頭的請求。

- match:
  - heraders:
      source:
        exact: north
    uri:
      prefix: "/advertisment"
  - uri:
      prefix: "/forecast"    

3)HTTP路由目標(HTTPRouteDestination)

HTTPRoute上的route字段是一個HTTPRouteDestination類型的數組,表示滿足條件的流量目標。在HTTPRouteDestination中主要由三個字段:destination(請求目標)、weight(權重)、和headers(HTTP頭操作),destination、weight是必選字段。
(1)destination
核心字段destination吧小時請求的目標。在Virtualservice 上執行一組規則,最終的流量要被送到這個目標上。這個字段是一個Destination類型結構,通過host、subset和port三個屬性來描述。
host是Destination必選字段,表示在Istio中註冊的服務名,不但包括網格內的服務,也包括通過ServiceEntry方式註冊的外部服務。在kubernetes平臺上如果使用短域名,Istio就會根據規則的命名空間解析服務名,而不是根據Service的命名空間來解析。所以在使用上建議寫全域名,這和VirtualService的hosts用法類似。
與host配合來表示流量路由後端的是另一個重要字段subset,它表示在host上定義的一個子集。例如,在灰度發佈中將版本定義爲subset,配置路由策略會將流量轉發到不同版本的subset上。

(2)weight
除了destination,HTTPRouteDestination上的另一個必選字段是weight,表示流量分配的比例,在一個route下多個destination的weight總和要求是100。
在下面示例,從原有的v1版本中切分20%的流量到v2版本,這也是灰度發佈常用的一個流量策略,即不區分內容,平等的從總流量中切出一部分流量給新版本。

.....
spec:
  hosts:
  - forecast
  http:
  - route:
    - destination:
        host: forecast
        subset: v2
      weight: 20
    - destination:
        host: forecast
        subset: v1
      weight: 80    

如果一個route只有一個destination,那麼可以省略weight,默認就是100.

(3)headers
headers字段提供了對HTTP header的一種操作機制,可以修改一次HTTP請求中的Request或Response的值,包含request和response兩個字段。

  • request:表示在發請求給目標地址時修改Request的header。
  • response:表示在返回應答時修改Response的header
    對應的類型都是HeaderOperations類型,使用set、add、remove字段來定義對Header的操作。
  • set:使用map上的key和value覆蓋Request和Response中對應的Header
  • add:追加map上的key和value到原有的Header
  • remove:刪除在列表中華指定的Header

以上分別介紹了HTTP請求匹配條件的定義和HTTP目標路由的定義,這也是HTTPRoute的主要功能。Istio對於HTTP除了做流量路由,還可以做適當的其他操作,很多原來需要在代碼中進行的HTTP操作,在使用Istio後通過這些配置都可以達到同樣的效果,下面分別進行講解。

4)HTTP重定向(HTTPRedirect)

我們通過HTTPRedirect可以發送一個301重定向的應答給服務調用方,簡單講就是從一個URL到另外一個URL的永久重定向。用戶輸入一個URL,通過HTTPRedirect可以將其跳轉到另一個URL。比較常見的場景:有一個在線網站,網址變了,通過這樣的重定向,可以在用戶輸入老地址時跳轉到新地址。
可以看下過程:

  1. 用戶請求老地址:http://forecast/advertisement
  2. 服務端返回301重定向新地址 http://new-forecast/recommendation/activity
  3. 用戶請求新地址http://new-forecast/recommendation/activity
  4. 得到新地址

HTTPRedirect包括兩個重要的字段來表示重定向的目標。

  • uri:替換URL中的uri部分
  • authority:替換URL中的Authority部分

需要注意的是,這裏使用HTTPRedirect的uri的配置會替換原請求中的完整Path,而不是匹配條件上的uri部分。如下所示,對forecast服務所有前綴是“/advertisement”的請求都會被重定向到new-forecast的“/recommendation/activity”地址:

apiVersion:networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: forecast
  namespace:weather
spec:
  hosts:
  - forecast
  http:
  - match:
    - uri: 
        prefix: /advertisement
    redirect:
      uri: /recommendation/activity
      authority: new-forecast    

5)HTTP重寫(HTTPRewrite)

通過HTTP重寫可以在將請求轉發給目標服務前修改HTTP請求中指定部分的內容,不同於重定向,用戶是可見,HTTP重寫對用戶是不可見的,因爲是在服務端進行的。
和重定向配置類似,重寫HTTP也包括uri和authority這兩個字段。

  • uri:重寫URL中的Path部分
  • authority:重寫URL中的Authority

和HTTPRedirect規則稍有不同的是,HTTPRedirect的uri只能替換全部的Path,HTTPRewrite的uri是可以重寫前綴的,即如果原來匹配條件是前綴匹配,則修改後只修改匹配到的前綴。
如下所示,前綴匹配“/advertisement”的請求,其請求uri中的這部分前綴會被“/recommendation/activity”替換:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: forecast
  namespace: weather
spec:
  hosts:
  - forecast
  http:
  - match:
    - uri:
        prefix: /advertisement
    rewrite:
      uri: /recommendation/activity
    route:
    - destination:
        host: forecast   

6)HTTP重試(HTTPRetry)

HTTP重試是解決很多請求異常最直接、簡單的方法,尤其是在工作環境比較複雜的場景下,克提高總體的服務質量。但是重試使用不當也會有問題,最糟糕的情況是重試一直不成功,反而增加延遲和性能開銷。所以,根據系統運行環境、服務自身特點,配置適當的重試規則顯得尤爲重要。
HTTPRetry可以定義請求失敗時的重試策略,重試策略包括重試次數、超時、重試條件等,這裏分別描述相應的三個字段。

  • attempts:必選字段,定義重試的次數
  • perTryTimeout:每次重試超時的時間,單位可以是ms、s、m和h
  • retryOn:進行重試的條件,可以是多個條件,以逗號分隔

其中重試條件retryOn的取值可以包括以下幾種。

  • 5xx:在上游服務返回5xx應答碼,或者在沒有返回時重試
  • gateway-error:類似於5xx異常,只對502、503和504應答碼進行重試。
  • connect-failure:在鏈接上游服務失敗時重試 retriable-4xx:在上游服務返回可重試的4xx應答碼時執行重試。
  • refused-stream:在上游服務使用REFUSED_STREAM錯誤碼重置時執行重試。
  • cancelled:gRPC應答的Header中狀態碼是cancelled時執行重試。
  • deadline-exceeded:在gRPC應答的Header中狀態碼是deadline-exceeded時執行重試
  • internal:在gRPC應答的Header中狀態碼是internal時執行重試
  • resource-exhausted:在gRPC應答的Header中狀態碼是resource-exhausted時執行重試
  • unavailable:在gRPC應答的Header中狀態碼是unavailable時執行重試。

如下所示,配置了一個重試策略,在“5xx,connect-failure”條件下進行最多5次重試,每次重試超時爲3秒:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
medata:
  name: forecast
  namespace: weather
spec:
  hosts:
  - forecast
  http:
  - route:
    - destination:
        host: forecast
    retries:
      attempts: 5
      perTryTimeout: 3s
      retryOn: 5xx,connect-failure    

7)HTTP流量鏡像(Mirror)

HTTP流量鏡像指的是將流量轉發到原目標地址的同時將流量給另外一個目標地址鏡像一份。把生產環境中的實際流量鏡像一份到另外一個系統上,完全不會對生產系統產生影響,這裏只是鏡像了一份流量,數據面代理只需要關注原來轉發的流量就可以,不用等待鏡像目標地址的返回。
如下所示:

apiVersion: networking.istio.io:v1alpha3
kind: VirtualService
metadata:
  name: forecast
  namespace: weather
spec:
  hosts:
    - forecast
  http:
  - route:
    - destination:
      host: forecast
      subset: v1
    mirror:
      host: forecast
      subset: v2 

8)HTTP故障注入(HTTPFaultInjection)

在場景上,與其說是HTTP支持Istio的故障注入,不如說是Istio的故障注入功能支持HTTP。在Istio中爲了支持非侵入的故障注入,要構造一定的業務故障,最好在HTTP這個通用的應用協議上有所支持。
實現上,在HTTP上做故障注入和前面的Redirect、Rewrite、Retry沒有太大的差別,都是修改HTTP請求或者應答的內容。需要注意的是,在使用故障注入時,不能啓用超時和重試。
HTTPFaultInjection通過delay和abort兩個字段設置延時和中止兩種故障,分別表示Proxy延遲轉發HTTP請求和中止HTTP請求。
(1)延遲故障注入
HTTPFaultInjection中的延遲故障使用HTTPFaultInjection.Delay 類型描述延時故障,表示在發送請求前進行一段延時,模擬網絡、遠端服務負載均衡等各種原因導致的失敗,主要是如下兩個字段:

  • fixedDelay:一個必選字段,表示延遲時間,單位可以是毫秒、秒、分鐘和小時,要求至少大於1毫秒
  • percentage:配置的延遲故障作用在多少的比例的請求上,通過這種方式可以只讓部分請求發生故障。

如下所示,表示forecast服務v1版本上的1.5%的請求產生10秒的延時:

......
route:
- destination:
    host: forecast
    subset: v1
fault:
  delay:
    percenttage:
      value: 1.5
    fixedDelay: 10s     

(2)請求中止故障注入
HTTPFaultInjection 使用HTTPFaultInjection.Abort 描述中止故障,模擬服務端異常,給調用的客戶端返回預先定義的錯誤狀態碼,主要有以下兩個字段。
httpStatus:是一個必選字段,表示中止的HTTP狀態碼
percentage:配置中止故障作用在多少比例的請求上,通過這種方式可以只讓部分請求發生故障,用法通延遲故障
如下所示,讓forecast服務v1版本上1.5%的請求返回“500”代碼

......
route:
- destination:
    host: forecast
    subset: v1
fault:
  abort:
    percnetage: 
      value: 1.5
    httpStatus: 500    

9)HTTP跨域資源共享(CorsPolicy)

當一個資源向該資源所在服務器的不同的域發起請求時,就會產生一個跨域的HTTP請求。出於安全考慮,瀏覽器會限制從腳本發起的跨域HTTP請求。通過跨域資源共享CORS(Cross Origin Resource Sharing)機制克允許web應用服務器進行跨域訪問控制,使跨域數據傳遞安全進行。在實現上是在HTTP Header中追加一些額外的信息來通知瀏覽器准許以上訪問。
在 VirtualService 中可以對滿足條件的請求配置跨域資源共享。有allowOrigin、allowMethods、allowHeader、exposeHeader、maxAge、allowCredentials,其實都是被轉化爲 Access-Control-* 的Header。 如下所示,允許源自news.com的GET方法的請求的訪問。

......
http:
- route:
  - destination:
      host: forecast
    corsPolicy:
      allowOrigin:
      - news.com
      allowMethods:
      - GET
      maxAge: "2d"    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章