随着系统越来越复杂,服务间的依赖也越来越多,当实现一个完整的功能时,只靠内部的服务是无法支撑的。且不说当前云原生环境下的复杂应用,就是在多年前的企业软件开发环境下,自己开发的程序也需要搭配若干中间件才能完成。
如图3-2 4所示,4个服务组成一个应用,后端依赖一个数据库服务,这就需要一种机制能将数据库服务接入并治理。在当前的云化场景下,这个数据库可以是部署的一个外部服务,也可以是一个RDS的云服务。在托管的云平台上搭建的应用一般都会访问数据库、分布式缓存等中间件服务。
图3-24 外部服务接入
关于这种第三方服务的管理,专门有一种Open Service Broker API来实现第三方软件的服务化,这种API通过定义Catalog、Provisioning、Updating、Binding、Unbinding等标准接口接入服务,在和Kubernetes结合的场景下,使用Service Catalog的扩展机制可以方便地在集群中管理云服务商提供的第三方服务,如图3-25所示。
图3-25 通过Open Service Broker API管理外部服务
Istio可以方便地对网格内的服务访问进行治理,那么如何对这种网格外的服务访问进行治理呢?从实际需求上看,对一个数据库访问进行管理,比对两个纯粹的内部服务访问进行管理更重要。在Istio中是通过一个ServiceEntry的资源对象将网格外的服务注册到网格上,然后像对网格内的普通服务一样对网格外的服务访问进行治理的。
如图3-26所示,在Pilot中创建一个ServiceEntry,配置后端数据库服务的访问信息,在Istio的服务发现上就会维护这个服务的记录,并对该服务配置规则进行治理,从forecast服务向数据库发起的访问在经过Envoy时就会被拦截并进行治理。
图3-26 以ServiceEntry方式接入外部服务
ServiceEntry是 Istio 中对网格外的服务的推荐使用方式,当然也可以选择不做治理,直接让网格内的服务访问网格外的服务。
在大多数时候,在访问网格外的服务时,通过网格内服务的 Sidecar 就可以执行治理功能,但有时需要有一个专门的Egress Gateway来支持,如上面的例子所示。出于对安全或者网络规划的考虑,要求网格内所有外发的流量都必须经过这样一组专用节点,需要定义一个Egress Gateway并分配Egress节点,将所有的出口流量都转发到Gateway上进行管理。
VirtualService是Istio流量治理的一个核心配置,可以说是Istio流量治理中最重要、最复杂的规则,本节详细讲解其定义和用法。
路由规则配置示例
在理解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版本上。
路由规则定义
VirtualService定义了对特定目标服务的一组流量规则。如其名字所示,VirtualService在形式上表示一个虚拟服务,将满足条件的流量都转发到对应的服务后端,这个服务后端可以是一个服务,也可以是在DestinationRule中定义的服务的子集。
VirtualService是在Istio V1alpha3版本的API中引入的新路由定义。不同于V1alpha1版本中RouteRule使用一组零散的流量规则的组合,并通过优先级表达规则的覆盖关系,VirtualService描述了一个具体的服务对象,在该服务对象内包含了对流量的各种处理,其主体是一个服务而不是一组规则,更易于理解。
VirtualService中的一些术语如下。
◎ Service:服务。
◎ Service Version:服务版本。
◎ Source:发起调用的服务。
◎ Host:服务调用方连接和调用目标服务时使用的地址,是 Istio的几个配置中非常重要的一个概念,后面会有多个地方用到,值得注意。
通过 VirtualService 的配置,应用在访问目标服务时,只需要指定目标服务的地址即可,不需要额外指定其他目标资源的信息。在实际请求中到底将流量路由到哪种特征的后端上,则基于在VirtualService中配置的路由规则执行。
如图3-27所示是VirtualService的完整规则定义,可以看出其结构很复杂,本节后续将逐级展开介绍。
图3-27 VirtualService的完整规则定义
先看下VirtualService第1级的定义,如图3-28所示,可以很清楚地看到,除了hosts、gateways等通用字段,规则的主体是http、tcp和tls,都是复合字段,分别对应HTTPRoute、TCPRoute和TLSRoute,表示Istio支持的HTTP、TCP和TLS协议的流量规则。
图3-28 VirtualService第1级的规则定义
非复合字段hosts和gateways是每种协议都要用到的公共字段,体现了VirtualService的设计思想。
(1) hosts:是一个重要的必选字段,表示流量发送的目标。可以将其理解为VirtualService定义的路由规则的标识,用于匹配访问地址,可以是一个DNS名称或IP地址。DNS 名称可以使用通配符前缀,也可以只使用短域名,也就是说若不用全限定域名FQDN,则一般的运行平台都会把短域名解析成FQDN。
对于Kubernetes平台来说,在hosts中一般都是Service的短域名。如forecast这种短域名在 Kubernetes 平台上对应的完整域名是“forecast.weather.svc.cluster.local”,其中weather 是 forecast 服务部署的命名空间。而在 Istio 中,这种短域名的解析基于VirtualService 这个规则所在的命名空间,例如在本节的示例中,hosts 的全域名是“forecast.default.svc.cluster.local”,这与我们的一般理解不同。建议在规则中明确写完整域名,就像在写代码时建议明确对变量赋初始值,而不要依赖语言本身的默认值,这样不但代码可读,而且可以避免在某些情况下默认值与期望值不一致导致的潜在问题,这种问题一般不好定位。
注意:VirtualService 的 hosts 的短域名解析到的完整域名时,补齐的 Namespace 是VirtualService的Namespace,而不是Service的Namespace。
hosts一般建议用字母的域名而不是一个IP地址。IP地址等多用在以Gateway方式发布一个服务的场景,这时hosts匹配Gateway的外部访问地址,当没有做外部域名解析时,可以是外部的IP地址。
(2)gateways:表示应用这些流量规则的 Gateway。VirtualService 描述的规则可以作用到网格里的 Sidecar 和入口处的 Gateway,表示将路由规则应用于网格内的访问还是网格外经过Gateway的访问。其使用方式有点绕,需要注意以下场景。
◎ 场景1:服务只是在网格内访问的,这是最主要的场景。gateways字段可以省略,实际上在VirtualService的定义中都不会出现这个字段。一切都很正常,定义的规则作用到网格内的Sidecar。
◎ 场景2:服务只是在网格外访问的。配置要关联的Gateway,表示对应Gateway进来的流量执行在这个VirtualService上定义的流量规则。
◎ 场景3:在服务网格内和网格外都需要访问。这里要给这个数组字段至少写两个元素,一个是外部访问的Gateway,另一个是保留关键字“mesh”。使用中的常见问题是忘了配置“mesh”这个常量而导致错误。我们很容易认为场景 3是场景 1和场景2的叠加,只需在内部访问的基础上添加一个可用于外部访问的Gateway。
注意:在 VirtualService 中定义的服务需要同时网格外部访问和内部访问时,gateways 字段要包含两个元素:一个是匹配发布成外部访问的Gateway名,另外一个是“mesh”这个关键字。
(3)http:是一个与 HTTPRoute 类似的路由集合,用于处理 HTTP 的流量,是 Istio中内容最丰富的一种流量规则。
(4)tls:是一个 TLSRoute 类型的路由集合,用于处理非终结的 TLS 和 HTTPS 的流量。
(5)tcp:是一个TCPRoute类型的路由集合,用于处理TCP的流量,应用于所有其他非 HTTP和 TLS端口的流量。如果在 VirtualService中对 HTTPS和 TLS没有定义对应的TLSRoute,则所有流量都会被当成TCP流量来处理,都会走到TCP路由集合上。
以上3个字段在定义上都是数组,可以定义多个元素;在使用上都是一个有序列表,在应用时请求匹配的第1个规则生效。
注意:VirtualService中的路由规则是一个数组,在应用时匹配的第1个规则生效就跳出,不会检查后面的规则。
(6) exportTo:是 Istio 1.1 在 VirtualService 上增加的一个重要字段,用于控制VirtualService 跨命名空间的可见性,这样就可以控制在一个命名空间下定义的VirtualService是否可以被其他命名空间下的Sidecar和Gateway使用了。如果未赋值,则默认全局可见。“.”表示仅应用到当前命名空间,“*”表示应用到所有命名空间。在Istio 1.1中只支持“.”和“*”这两种配置。