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“ 用户的所有请求,所以使用 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/