Istio虛擬服務 (Virtual Service)


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“ 用戶的所有請求,所以使用 headersend-user 和 exact 字段選擇適當的請求。

- match:
   - headers:
       end-user:
         exact: jason

destination字段

route 部分的 destination 字段指定了符合此條件的流量的實際目標地址。與虛擬服務的 hosts 不同,destination 的 host 必須是存在於 Istio 服務注冊中心的實際目標地址(k8s服務名),否則 Envoy 不知道該將請求發送到哪里。可以是一個有代理的服務網格,或者是一個通過服務入口被添加進來的非網格服務。本示例運行在 Kubernetes 環境中,host 名為一個 Kubernetes 服務名: 

   route:
      - destination:
          host: httpd-service

請注意,在該示例和本頁其它示例中,為了簡單,我們使用 Kubernetes 的短名稱設置 destination 的 host。在評估此規則時,Istio 會添加一個基於虛擬服務命名空間的域后綴(服務名.namespace.svc.cluster.local),這個虛擬服務包含要獲取主機的完全限定名的路由規則。在我們的示例中使用短名稱也意味着您可以復制並在任何喜歡的命名空間中嘗試它們。 只有在目標主機和虛擬服務位於相同的 Kubernetes 命名空間時才可以使用這樣的短名稱。因為使用 Kubernetes 的短名稱容易導致配置出錯,我們建議您在生產環境中指定完全限定的主機名。destination 片段還指定了 Kubernetes 服務的子集,將符合此規則條件的請求轉入其中。您可以在目標規則章節中看到如何定義服務子集。

路由規則優先級

路由規則按從上到下的順序選擇,虛擬服務中定義的第一條規則有最高優先級。本示例中,不滿足第一個路由規則的流量均流向一個默認的目標,該目標在第二條規則中指定。因此,第二條規則沒有 match 條件,直接將流量導向nginx-service服務。

- route:
    - destination:
        host: nginx-service

在生產環境中建議提供一個默認的“無條件”或基於權重的規則作為每一個虛擬服務的最后一條規則,如案例所示,從而確保流經虛擬服務的流量至少能夠匹配一條路由規則。

路由規則的更多內容

正如上面所看到的,路由規則是將特定流量子集路由到指定目標地址的強大工具。您可以在流量端口、header 字段、URI 等內容上設置匹配條件。例如,這個虛擬服務讓用戶發送請求到兩個獨立的服務:ratings 和 reviews,就好像它們是 http://bookinfo.com/ 這個更大的虛擬服務的一部分。虛擬服務規則根據請求的 URI 和指向適當服務的請求匹配流量。

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
...

  http:
  - match:
      sourceLabels:
        app: reviews
    route:
...

有些匹配條件可以使用精確的值,如前綴或正則。

您可以使用 AND 向同一個 match 塊添加多個匹配條件,或者使用 OR 向同一個規則添加多個 match 塊。對於任何給定的虛擬服務也可以有多個路由規則。這可以在單個虛擬服務中使路由條件變得隨您所願的復雜或簡單。匹配條件字段和備選值的完整列表可以在 HTTPMatchRequest 參考中找到。

另外,使用匹配條件您可以按百分比”權重“分發請求。這在 A/B 測試和金絲雀發布中非常有用:

spec:
  hosts:
  - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1
      weight: 75
    - destination:
        host: reviews
        subset: v2
      weight: 25

您也可以使用路由規則在流量上執行一些操作,例如:

  • 添加或刪除 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/

參考:https://zhuanlan.zhihu.com/p/262249783


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM