3.2 核心配置对象
Istio在安装过程中会进行CRD的初始化,在Kubernetes集群中注册一系列的CRD。CRD在注册成功之后,会建立一些基础对象,完成Istio的初始设置。
在前面介绍组件时曾多次提到,用户利用Istio控制微服务通信,是通过向Kubernetes提交CRD资源的方式完成的。Istio中的资源分为三组进行管理,分别是networking.istio.io、config.istio.io及authentication.istio.io,下面将分别进行介绍。
3.2.1 networking.istio.io
networking.istio.io系列对象在Istio中可能是使用频率最高的,Istio的流量管理功能就是用这一组对象完成的,这里选择其中最常用的对象进行简单介绍。
在networking.istio.io的下属资源中,VirtualService是一个控制中心。它的功能简单说来就是:定义一组条件,将符合该条件的流量按照在对象中配置的对应策略进行处理,最后将路由转到匹配的目标中。下面列出几个典型的应用场景。
(1)来自服务A版本1的服务,如果要访问服务B,则要将路由指向服务B的版本2。
(2)在服务X发往服务Y的HTTP请求中,如果Header包含“canary=true”,则把服务目标指向服务Y的版本3,否则发给服务Y的版本2。
(3)为从服务M到服务N的所有访问都加入延迟,以测试在网络状况不佳时的表现。
可以看出,这方面的功能是比较复杂的,因此其中包含的行为定义也一定不简单。Istio对路由管理做了很好的抽象。图3-5展示了流量访问流程中的几个关键对象。
图3-5
1.Gateway
在访问服务时,不论是网格内部的服务互访,还是通过Ingress进入网格的外部流量,首先要经过的设施都是Gateway。Gateway对象描述了边缘接入设备的概念,其中包含对开放端口、主机名及可能存在的TLS证书的定义。网络边缘的Ingress流量,会通过对应的Istio Ingress Gateway Controller进入;网格内部的服务互访,则通过虚拟的mesh网关进行(mesh网关代表网格内部的所有Sidecar)。
Pilot会根据Gateway和主机名进行检索,如果存在对应的VirtualService,则交由VirtualService处理;如果是Mesh Gateway且不存在对应这一主机名的VirtualService,则尝试调用Kubernetes Service;如果不存在,则发生404错误。
2.VirtualService
VirtualService对象主要由以下部分组成。
(1)Host:该对象所负责的主机名称,如果在Kubernetes集群中,则这个主机名可以是服务名。
(2)Gateway:流量的来源网关,在后面会介绍网关的概念。如果这一字段被省略,则代表使用的网关名为“mesh”,也就是默认的网格内部服务互联所用的网关。
(3)路由对象:网格中的流量,如果符合前面的Host和Gateway的条件,就需要根据实际协议对流量的处理方式进行甄别。其原因是:HTTP是一种透明协议,可以经过对报文的解析,完成更细致的控制;而对于原始的TCP流量来说,就无法完成过于复杂的任务了。
3.TCP/TLS/HTTP Route
路由对象目前可以是HTTP、TCP或者TLS中的一个,分别针对不同的协议进行工作。每种路由对象都至少包含两部分:匹配条件和目的路由。例如,在HTTPRoute对象中就包含用于匹配的HTTPMatchRequest对象数组,以及用于描述目标服务的DestinationWeight对象,并且HTTPMatchRequest的匹配条件较为丰富,例如前面提到的http header或者uri等。除此之外,HTTP路由对象受益于HTTP的透明性,包含很多专属的额外特性,例如超时控制、重试、错误注入等。相对来说,TCPRoute简单很多,它的匹配借助资源L4MatchAttributes对象完成,其中除Istio固有的源标签和Gateway外,仅包含地址和端口。
在匹配完成后,自然就是选择合适的目标了。
4.DestinationWeight
各协议路由的目标定义是一致的,都由DestinationWeight对象数组来完成。DestinationWeight指到某个目标(Destination对象)的流量权重,这就意味着,多个目标可以同时为该VirtualService提供服务,并按照权重进行流量分配。
5.Destination
目标对象(Destination)由Subset和Port两个元素组成。Subset顾名思义,就是指服务的一个子集,它在Kubernetes中代表使用标签选择器区分的不同Pod(例如两个Deployment)。Port代表的则是服务的端口。
6.小结
至此,流量经过多个对象的逐级处理,成功到达了Pod,在第7章会通过不同的案例来展示与Istio流量管理相关的功能。
3.2.2 config.istio.io
config.istio.io中的对象用于为Mixer组件提供配置。在3.1节中讲到,Mixer提供了预检和报告这两个功能,这两个功能看似简单,但是因为大量适配器的存在,变得相当复杂。图3-6简单展示了Mixer对数据的处理过程。
图3-6
1.Rule
Rule对象是Mixer的入口,其中包含一个match成员和一个逻辑表达式,只有符合表达式判断的数据才会被交给Action处理。逻辑表达式中的变量被称为attribute(属性),其中的内容来自Envoy提交的数据。
2.Action
Action负责解决的问题就是:将符合入口标准的数据,在用什么方式加工之后,交给哪个适配器进行处理。Action包含两个成员对象:一个是Instance,使用Template对接收到的数据进行处理;一个是Handler,代表一个适配器的实例,用于接收处理后的数据。
3.Instance
Instance主要用于为进入的数据选择一个模板,并在数据中抽取某些字段作为模板的参数,传输给模板进行处理。
4.Adapter
Adapter在Istio中只被定义为一个行为规范,而一些必要的实例化数据是需要再次进行初始化的,例如RedisQuota适配器中的Redis地址,或者listchecker中的黑白名单等,只有这些数据得到正式的初始化,Adapter才能被投入使用。
经过Handler实例化之后的Adapter,就具备了工作功能。有些Adapter是Istio的自身实现,例如前面提到的listchecker或者memquota;有些Adapter是第三方服务,例如Prometheus或者Datadog等。Envoy传出的数据将会通过这些具体运行的Adapter的处理,得到预检结果,或者输出各种监控、日志及跟踪数据。
5.Template
顾名思义,Template是一个模板,用于对接收到的数据进行再加工。
进入Mixer中的数据都来自Sidecar,但是各种适配器应对的需求各有千秋,甚至同样一个适配器,也可能接收各种不同形式的数据(例如Prometheus可能会在同样一批数据中获取不同的指标), Envoy提供的原始数据和适配器所需要的输入数据存在格式上的差别,因此需要对原始数据进行再加工。
Template就是这样一种工具,在用户编制模板对象之后,经过模板处理的原始数据会被转换为符合适配器输入要求的数据格式,这样就可以在Instance字段中引用了。
6.Handler
Handler对象用于对Adapter进行实例化。
这组对象的命名非常令人费解,但是从其功能列表中可以看出,Mixer管理了所有第三方资源的接入,大大扩展了Istio的作用范围,其应用难度自然水涨船高,应该说还是可以理解的。
3.2.3 authentication.istio.io
这一组API用于定义认证策略。它在网格级别、命名空间级别及服务级别都提供了认证策略的要求,要求在内容中包含服务间的通信认证,以及基于JWT的终端认证。这里简单介绍其中涉及的对象。
1.Policy
Policy用于指定服务一级的认证策略,如果将其命名为“default”,那么该对象所在的命名空间会默认采用这一认证策略。
Policy对象由两个部分组成:策略目标和认证方法。
◎ 策略目标包含服务名称(或主机名称)及服务端口号。
◎ 认证方法由两个可选部分组成,分别是用于设置服务间认证的peers子对象,以及用于设置终端认证的origins子对象。
2.MeshPolicy
MeshPolicy只能被命名为“default”,它代表的是所有网格内部应用的默认认证策略,其余部分内容和Policy一致。
3.2.4 rbac.istio.io
在Istio中实现了一个和Kubernetes颇为相似的RBAC(基于角色的)访问控制系统,其主要对象为ServiceRole和ServiceRoleBinding。
1.ServiceRole
ServiceRole由一系列规则(rules)组成,每条规则都对应一条权限,其中描述了权限所对应的服务、服务路径及方法,还包含一组可以进行自定义的约束。
2.ServiceRoleBinding
和Kubernetes RBAC类似,该对象用于将用户主体(可能是用户或者服务)和ServiceRole进行绑定。