1、概述
虛擬服務(Virtual Service) 和目標規則(Destination Rule) 是 Istio 流量路由功能的關鍵拼圖。虛擬服務讓您配置如何在服務網格內將請求路由到服務,這基於 Istio 和平台提供的基本的連通性和服務發現能力。每個虛擬服務包含一組路由規則,Istio 按順序評估它們,Istio 將每個給定的請求匹配到虛擬服務指定的實際目標地址。您的網格可以有多個虛擬服務,也可以沒有,取決於您的使用場景。
2、有了 Kubernetes Service,為什么還需要 Istio Virtual Service
簡單來說,基於 Kubernetes Service,只可以實現簡單的流量負載均衡,如果想實現基於HTTP Header,負載百分比等等復雜的流量控制就無從下手了,Istio Vistrual Service在原本 Kubernetes Service 的功能之上,提供了更加豐富的路由控制。
3、virtualservices.networking.istio.io資源結構
通過kubectl get customresourcedefinitions.apiextensions.k8s.io virtualservices.networking.istio.io -o yaml命令查看virtualservices資源的apiGroups、apiVersions 和 resources 以及資源的 scope信息,可以看到資源scope是Namespaced。
spec: conversion: strategy: None group: networking.istio.io names: categories: - istio-io - networking-istio-io kind: VirtualService listKind: VirtualServiceList plural: virtualservices shortNames: - vs singular: virtualservice scope: Namespaced .....
4、Virtual Service示例
有兩個Deployment(nginx 及 httpd),通過Service關聯到一起,通過訪問Service只能做到簡單的負載均衡,通過實驗發現 nginx 和 httpd 流量各自在 50% 左右。
Deployment和Service配置文件如下:
apiVersion: apps/v1 kind: Deployment metadata: labels: app: nginx name: nginx-deployment spec: replicas: 1 selector: matchLabels: app: nginx strategy: rollingUpdate: maxSurge: 25% maxUnavailable: 25% type: RollingUpdate template: metadata: labels: app: nginx server: web spec: containers: - image: 'nginx:latest' name: nginx-deployment --- apiVersion: apps/v1 kind: Deployment metadata: labels: app: httpd name: httpd-deployment spec: replicas: 1 selector: matchLabels: app: httpd strategy: rollingUpdate: maxSurge: 25% maxUnavailable: 25% type: RollingUpdate template: metadata: labels: app: httpd server: web spec: containers: - image: 'httpd:latest' name: httpd-deployment --- apiVersion: v1 kind: Service metadata: name: nginx-service spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: nginx type: ClusterIP --- apiVersion: v1 kind: Service metadata: name: httpd-service spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: httpd type: ClusterIP --- apiVersion: v1 kind: Service metadata: name: web-service spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: server: web type: ClusterIP
如果想實現更加細顆粒度的流量管控,通過引入Istio Vistrual Service 非常簡單的就實現復雜的流量管理。VirtualService 根據 destination 進行調度,並且設置相關的負載百分比實現精准的控制。
apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: web-vs #name可以隨便取值 spec: hosts: - web-service #hosts值必須是kubernetes里面的服務名 http: - route: - destination: host: nginx-service #k8s服務名 weight: 80 - destination: host: httpd-service weight: 20
通過客戶端測試以上的實驗,客戶端也必須經過 Istio 注入,因為只有客戶端被 Istio 注入才可以接收到來自 Pilot 有關 Virtual Service 和 Destination Rule 的配置信息,才可以保證流量接管生效。
apiVersion: apps/v1 kind: Deployment metadata: labels: app: client-deployment name: client-deployment spec: replicas: 1 selector: matchLabels: app: client-deployment strategy: rollingUpdate: maxSurge: 25% maxUnavailable: 25% type: RollingUpdate template: metadata: labels: app: client-deployment spec: containers: - image: 'busybox:latest' name: client-deployment command: [ "/bin/sh", "-c", "sleep 3600"]
進入客戶端容器執行 wget -q -O - web-service
觀察執行結果,可以測試出nginx流量在80%左右,httpd 流量在20%左右。
這里解釋下 wget -q -O -含義:
-q的含義是:--quiet,安靜模式,無信息輸出。
-O的含義是把后面網址下載后,改成一個指定的名稱,如果后面沒有跟着一個名字,而是“-”,則表示將下載后的內容輸出到標准輸出,也就是輸出到屏幕上。
-qO-的含義:把下載的內容輸出到標准輸出
5、Vistrual Service配置詳解
除了權重之外,還有條件匹配,很多場景下,需要針對不同的用戶已提供個性化的服務等,例如針對地理位置、是否為VIP等等,那就需要對http流量進行識別匹配,示例如下:
apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: web-vs spec: hosts: - web-service http: - match: - headers: end-user: exact: jason uri: prefix: "/health" ignoreUriCase: true route: - destination: host: httpd-service - route: - destination: host: nginx-service
5.1 hosts字段
使用 hosts
字段列舉虛擬服務的主機——即用戶指定的目標或是路由規則設定的目標。這是客戶端向服務發送請求時使用的一個或多個地址。
hosts: - web-service #hosts值如果是域名形式必須是kubernetes里面的服務名
在Kubernetes里面虛擬服務主機名是k8s服務clusterIp或者k8s服務的短名稱(Pod DNS配置文件里面的search域會自動拼成"服務名.namespace.svc.cluster.local"形式),隱式或顯式地指向一個完全限定域名(FQDN)。您也可以使用通配符(“*”)前綴,讓您創建一組匹配所有服務的路由規則。虛擬服務的 hosts 字段實際上不必是 Istio 服務注冊的一部分,它只是虛擬的目標地址。這讓您可以為沒有路由到網格內部的虛擬主機建模。
5.2 路由規則(match 字段、destination字段)
match 字段
在 http
字段包含了虛擬服務的路由規則,用來描述匹配條件和路由行為,它們把 HTTP/1.1、HTTP2 和 gRPC 等流量發送到 hosts 字段指定的目標(您也可以用 tcp
和 tls
片段為 TCP 和未終止的 TLS 流量設置路由規則)。一個路由規則包含了指定的請求要流向哪個目標地址,具有 0 或多個匹配條件,取決於您的使用場景。
示例中的第一個路由規則有一個條件,因此以 match
字段開始。在本例中,您希望此路由應用於來自 ”jason“ 用戶的所有請求,所以使用 headers
、end-user
和 exact
字段選擇適當的請求。
- match: - headers: end-user: exact: jason
路由規則優先級
路由規則按從上到下的順序選擇,虛擬服務中定義的第一條規則有最高優先級。本示例中,不滿足第一個路由規則的流量均流向一個默認的目標,該目標在第二條規則中指定。因此,第二條規則沒有 match 條件,直接將流量導向nginx-service服務。
- route: - destination: host: nginx-service
路由規則的更多內容
正如上面所看到的,路由規則是將特定流量子集路由到指定目標地址的強大工具。您可以在流量端口、header 字段、URI 等內容上設置匹配條件。例如,這個虛擬服務讓用戶發送請求到兩個獨立的服務:ratings 和 reviews,就好像它們是 http://bookinfo.com/
這個更大的虛擬服務的一部分。虛擬服務規則根據請求的 URI 和指向適當服務的請求匹配流量。
您可以使用 AND 向同一個 match
塊添加多個匹配條件,或者使用 OR 向同一個規則添加多個 match
塊。對於任何給定的虛擬服務也可以有多個路由規則。這可以在單個虛擬服務中使路由條件變得隨您所願的復雜或簡單。匹配條件字段和備選值的完整列表可以在 HTTPMatchRequest
參考中找到。
另外,使用匹配條件您可以按百分比”權重“分發請求。這在 A/B 測試和金絲雀發布中非常有用:
- 添加或刪除 header。
- 重寫 URL。
- 為調用這一目標地址的請求設置重試策略。
想了解如何利用這些操作,查看 HTTPRoute
參考。
6、總結
在Kubernetes集群里面可以通過Istio Vistrual Service實現基於HTTP Header,負載百分比等等復雜的流量控制,相比於Kubernetes Service,它提供了更加豐富的路由控制。Vistrual Service資源scope是Namespaced級別的,Pod只有被Istio注入才可以接收到來自 Pilot 有關 Virtual Service 和 Destination Rule 的配置信息,才可以保證流量接管生效。Vistrual Service路由規則按從上到下的順序選擇,虛擬服務中定義的第一條規則有最高優先級,在生產環境中建議提供一個默認的“無條件”或基於權重的規則作為每一個虛擬服務的最后一條規則,這樣才能確保流經虛擬服務的流量至少能夠匹配一條路由規則。
參考:https://istio.io/latest/zh/docs/concepts/traffic-management/