1.服务网格的功能
流量管理:这是服务网格最核心的功能。比如动态路由,可以通过配置路由规则来动态确定要请求的服务。请求需要被路由到生产环境还是预发布环境,测试版本还是运行版本,仅针对登录用户还是全部用户?所有这些路由规则都可以以声明式方式进行配置。
策略:为应用添加一些请求控制策略,比如黑/白名单、限流等。
安全:既然持有了流量,自然可以针对流量做一系列的认证和授权操作,比如为流量添加双向TLS等。
可观察性:请求中必然包含很多可用信息,这些信息可以通过服务网格被收集并上报到对应的后端处理系统(如Prometheus),然后以各种可视化的方式被展示出来,以便开发者可以全面监控和观察应用的运行状态。
2.服务网格的优势
与应用解耦:非功能性需求都由边车代理实现,不需要在业务逻辑中添加控制逻辑。
云原生模式:服务网格具有云原生技术的典型特性,通过声明式配置来使用,对应用无侵入性且方便维护。
多语言支持:作为独立运行的透明代理,不受技术栈的约束,支持多语言的异构微服务应用。
多协议支持:可以支持多种协议。
3.使用Istio服务网格进行流量管理
Istio的流量管理能力主要体现在以下三个方面。
动态路由和流量转移:基本路由设置,按比例流量切分等。
弹性能力:超时、重试、熔断、限流。
流量调试:故障注入、流量镜像。
VirtualService
Kubernetes里的Service对象是Pod的访问入口,VirtualService就是Service对象的抽象访问入口,即将请求指引到对应的Service对象。其实VirtualService本质上就是一些路由规则,请求可以依据这些规则被分发到对应的服务。
(1)统一访问入口(请求分发)
根据URL将请求分发到不同服务的功能,和Gateway资源配合,适用于统一请求入口的场景。
(2)按比例流量切分
通过子集标签实现将流量切分到不同的服务(版本)中去,即灰度发布。
(3)超时、重试
VirtualService里提供timeout和retries两个关键字,实现超时与重试功能。
(4)故障注入
混沌工程是通过模拟实验可以验证在故障发生时应用的应对情况。
Istio使用fault关键字提供简单的故障注入功能。
延迟故障:使用delay关键字配置,给服务增加一个响应延迟。
中止故障:使用abort关键字设置,中止服务响应,模拟服务直接返回错误状态码的情况,比如返回500错误状态码。
(5)流量镜像
流量镜像就是将流量复制一份并实时将其发送到镜像服务。这个功能在调试线上问题的时候特别有用。
在VirtualService里通过mirror字段就可以设置
DestinationRule
DestinationRule一般和VirtualService配合使用。
VirtualService决定了请求去到哪个目标地址,而DestinationRule决定了请求到了这个目标地址后该如何被处理,它的主要功能有三个。
子集定义:通过定义子集将请求按不同的维度进行划分,配合VirtualService使用。
流量策略定义:定义请求到了目标地址后的处理方式,比如负载均衡、连接池大小等。
熔断:通过错误探测设置熔断效果。
(1)子集定义
VirtualService的destination字段里添加的subset要在这里定义好,同时在Pod里设置对应的version标签,请求就能被分发到对应的目标Pod里。
(2)流量策略定义
DestinationRule还负责定义流量策略,比如负载均衡的方式、连接池等。
(3)熔断
熔断是一种服务的降级处理方式,它比超时和重试更智能一些,可以自动探测服务的可用性并让服务从断流恢复到正常状态。与超时、重试不同的是,它是通过设置DestinationRule中的outlierDetection字段实现的。
ServiceEntry
ServiceEntry提供了一种访问外部服务流量的管理方式。它相当于一个外部服务在服务网格内的抽象代理,通过它能够在服务注册表中注册外部服务,其他服务网格内的服务就能像访问内部服务一样访问它。
WorkloadEntry
WorkloadEntry对象,它可以将非Kubernetes工作负载纳入服务网格的管理中。WorkloadEntry需要和ServiceEntry配合使用。WorkloadEntry定义工作负载的IP地址信息,并为该负载上的应用添加一个app标签;ServiceEntry在自己的选择器里填写相同的标签,
实现与WorkloadEntry的协同工作。
Gateway
外部请求想要访问服务网格内的服务,或者服务网格内的流量想通过统一的出口出去,就需要用到Gateway这个资源,即网关。Istio里提供了两种类型的网关,一种是Ingress入口网关,另一种是Egress出口网关,分别对应上面的两种应用场景。你可以将Gateway简单理解为接收传入或传出请求时在网格边缘运行的一个负载均衡器。需要注意的是,Istio里的Gateway只用来定义一个网关的基本信息,比如公开的端口、要使用的协议类型等,具体的路由规则还是要定义到VirtualService中,通过gateways字段进行匹配。这种设计和Kubernetes中的Ingress有所不同,它能分离网关的定义和路由信息,做到松散耦合。
Sidecar
默认情况下,Istio里的Envoy代理可以监听所有端口上的流量,并将流量转发到服务网格内的任意服务中。配置Sidecar资源可以改变这一默认行为,具体如下。
修改边车代理监听的端口和协议集合。
限制边车代理可以访问的服务。
Sidecar可以帮助微调边车代理的行为,或者对不同的代理使用不同的策略。
4.通过Istio实现熔断、超时与重试
熔断
熔断器是保证服务调⽤快速恢复能⼒的⼀个重要模式。在服务⽹格实现中,服务代理会监控与对⽬标服务调⽤相关的⼀些指标,⽐如当前的并发连接数量和等待处理的请求数量等。如果这些指标超过预先设定的阈值,则说明⽬标服务当前处于过载的状态,在这种情况下,应该暂时中断对⽬标服务的请求,使得后续对该服务的请求都直接快速失败,⽽不是继续等待。
在添加了熔断器之后,当⽬标服务过载时,与之对应的熔断器处于打开状态,终⽌后续的相关请求。在⼀段时间过后,熔断器会闭合,允许再次尝试调⽤⽬标服务。通过熔断器模式,可以避免服务的调⽤⽅等待过长的时间,⽽造成请求积压,从⽽导致服务的级联崩溃。
超时与重试
在⼀个微服务内部,当调⽤其他内部微服务或第三⽅服务的 API 时,都应该设置超时时间,这样,可以避免调⽤请求长时间处于等待状态。超时时间的设置取决于服务之间的服务级别协议(Service-level Agreement,SLA)。每个服务提供者都应该声明它在响应时间上的保证,⽐如,保证 90% 的请求都在 1 秒内给出响应。服务消费者根据服务级别协议来设置超时时间,⽐如,如果希望保证 90% 的请求都不超时,那么超时时间应该设置为 1 秒。
在没有服务⽹格之前,需要在代码中直接设置超时时间,⼀般通过服务客户端的 API 来完成。常见的做法是把超时时间设置以系统属性或环境变量的形式暴露出来,允许在运⾏时进⾏修改。不过这种⽅式的弊端在于,每次修改配置都会造成应⽤的重启。在 Istio 的虚拟服务资源中,HTTP 类型的路由可以使⽤ timeout 属性来设置超时时间。
当调⽤服务的请求出现错误时,如果该请求是幂等的,也可以对该请求进⾏重试。Istio 的服务代理提供了⾃动重试的功能,只需要在虚拟服务中进⾏配置即可。
5.通过istio实现追踪服务性能指标
服务性能指标
服务性能指标指的是记录每个服务在运⾏时的性能指标数据,包括访问次数和响应时间等;
调⽤追踪指的是对于每个请求,记录该请求在不同服务之间的调⽤关系。
服务性能指标和调⽤追踪两个功能相辅相成。在系统的运⾏过程中,通过监控服务性能指标可以发现系统中的异常情况。⽐如某个服务的响应时间突然出现了很⼤的延迟,具体的原因可能来⾃服务⾃⾝,也可能是由于来⾃调⽤者的请求变多。这些情况有时候是正常的,⽐如外部⽤户的访问量变⼤,造成整个系统的负载变⼤;有些情况是异常的,⽐如由于调⽤者出现了 Bug,造成了调⽤请求过多。为了定位问题,就需要查看并⽐对所有关联服务在同⼀时间段之内的性能指标。
Istio 的服务代理已经提供了⼀些性能指标数据,其在这基础上添加对 Prometheus 和 Grafana 的集成。Prometheus ⽤来收集性能指标数据,⽽ Grafana ⽤来提供图形化界⾯进⾏展⽰。
服务追踪
分布式追踪中最基本的概念是痕迹(Trace)和跨度(Span)。痕迹是操作的历史轨迹,通常与⼀个业务⾏为相对应,也可以是任意感兴趣的动作。痕迹由相互嵌套的跨度组成,跨度表⽰的是痕迹中的单个操作。
同⼀个痕迹中的不同跨度之间可能存在引⽤关系。最典型的引⽤关系是⽗⼦关系,也就是⽗跨度所对应操作的结果,依赖于⼦跨度所对应操作的结果。这种⽗⼦关系可以与编程语⾔中的⽅法调⽤形成的调⽤栈进⾏类⽐。需要被追踪的⽅法是整个痕迹的⼊⼜。每当这个⽅法调⽤其他⽅法时,会创建新的⼦跨度。这种⽅式递归下去,就形成了完整的痕迹。
为了能够记录完整的痕迹,在记录属于同⼀痕迹的不同跨度时,需要传递与痕迹相关的上下⽂对象。该上下⽂对象的作⽤是把可能产⽣在不同系统中的跨度串联起来,组织在同⼀个痕迹中。该上下⽂对象的具体格式,与使⽤的分布式追踪系统相关。
服务代理可以拦截对服务的调⽤请求。如果需要追踪服务之间的调⽤情况,服务代理可以在接收到请求之后,⾃动创建出相应的跨度,并发送到追踪服务器。Istio 提供了对⼀些追踪服务的⽀持,包括Zipkin、Jaeger 和 Lightstep 等。
应用服务追踪
第⼀种参与⽅式是只进⾏简单的上下⽂传播,不添加新的跨度,这种情况下,只需要传递上下⽂对象即可。接收到的请求中已经包含了与跨度上下⽂相关的 HTTP 头,当该服务调⽤其他微服务的 API 时,需要把同样的 HTTP 头传递过去。这样才可以保证追踪痕迹不中断。
第⼆种参与⽅式是添加新的跨度。当需要追踪⼀个服务内部的处理流程时,可以使⽤追踪实现的客户端来添加新的跨度。在调⽤其他微服务的 API 时,需要传递的是新的跨度上下⽂,其中痕迹的标识符保持不变,但是⽗跨度标识符会变成新创建的跨度。
6.通过istio实现服务访问控制与双向TLS
⾝份标识
⾝份标识⽤来区分不同的实体,在进⾏认证和授权时,都需要使⽤这个⾝份标识。服务⽹格中的⾝份标识分成服务标识和⽤户标识两类。
服务标识⽤来确定服务⽹格中的参与者,代表请求的发起者和响应者。在 Kubernetes 上,Istio 使⽤服务账户(Service Account)来作为⾝份标识。每个服务在部署时,都会创建各⾃独⽴的服务账户。
⽤户标识与具体的应⽤相关,⼀般以⽤户 ID、⽤户名或 Email 地址来表⽰。服务代理可以从请求中抽取出⽤户标识,⽐较典型的做法是在 JWT 令牌的 sub 申明中保存⽤户标识。
⾝份认证
策略
Istio 使⽤⾃定义资源来表⽰⾝份认证策略。策略有不同的应⽤范围,根据策略资源所在的名称空间和 selector 字段的值来划分。
对等认证策略只能有⼀个服务⽹格范围的策略,每个名称空间只能有⼀个该名称空间对应的策略,每个⼯作负载也只能有⼀个匹配的策略。对于同⼀个范围,如果存在多个匹配的策略,会应⽤创建时间最早的策略。
双向TLS
双向 TLS 可以验证服务双⽅的⾝份,同时对服务之间的传输进⾏加密。每个服务的⾝份由 X.509 证书来标识,Istio 则提供密钥和证书的管理。Istio 有⾃⼰的证书权威机构,可以为每个服务代理签发证书。在 Istio 的服务代理边车容器的运⾏过程中,Istio 的代理程序与证书权威机构进⾏交互,并把密钥和签发的证书通过 Envoy 的密钥发现服务,提供给 Envoy。由于 Istio 提供了对证书的管理,启⽤双向 TLS 就变得很简单。
请求认证
Istio 通过 JWT 来进⾏请求认证,可以与 OpenID Connect 提供者进⾏集成。这些提供者可以运⾏在集群内部,也可以是第三⽅的在线服务。
访问控制
Istio 的访问控制由 AuthorizationPolicy 资源来表⽰:
selector 应⽤该策略的⼯作负载的选择器。当选择器为空时,策略应⽤于当前名称空间的全部⼯作负载
rules 匹配请求的规则的列表
action 当请求匹配时的动作