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