文章目录
流量治理
istio在namespace中开启自动注入后,我们不再需要关心sidecar的生命周期与生效时间。进行流量治理的时候我们只需要与istio交互即可
在(一)中我们已经了解了Istio是通过k8的service进行服务发现的,所以即使我们的服务没有对外服务的能力,如果需要被istio接管的话也需要配置service(istio接近所有的流量治理方式都需要基于service操作
)
使用istio的注意事项
istio对k8的service依赖很深,所以在使用时也存在一些硬性要求
- 服务关联:pod需要关联到服务,如果一个pod关联到多个服务,则要求服务不能同一个端口上使用不同的协议。(
在istio的0.8版本以前为了满足这一需求,istio是不允许一个pod关联到多个服务的
) - deployment标签:istio建议deployment中显式的使用app和version标签,每个deployment都包含一个有业务意义的app标签和一个代表版本的version标签。这样istio在分布式追踪时可以通过app标签补齐上下文信息,并且可以通过app和version为遥测补齐信息
istio的流量治理流程
控制层
(1)管理员通过命令行或API创建流量规则
(2)Pilot组件(上一节中介绍过,Pilot组件类似一个master服务的功能会下发路由规则给每一个Sidecar,除了下发以外Pilot还有一个类似于解释器的功能,将用户配置的规则翻译成每个sidecar能识别的格式
)将流量规则转换为Envoy可以识别的标准格式;
(3)Polot组件将规则下发给Envoy
数据层
(1)Envoy拦截对应pod的IO流量
(2)Envoy在拦截到流量时根据收到的规则将流量治理
Istio的流量治理主要通过VirtualService(路由规则
)、DestinationRule(目标规则
)、Gateway(服务网关
)、ServiceEntry(外部服务
)来实现,其中我们最多使用的就是VS和DR
VirtualService路由规则配置
virtualService是istio最主要最复杂的核心配置,主要负责配置服务的调用规则,分发规则等等,在详细介绍vs功能之前,可以先查看以下的简化配置内容
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- match:
- headers:
end-user:
exact: jason
route:
- destination:
host: reviews
subset: v2
- route:
- destination:
host: reviews
subset: v1
- metadata_name: vs的名称
- spec_hosts: 对应服务的service名称
- spec_http_match: 路由规则
上面表达式的内容解说过来为:对reviews服务的访问请求中,如果请求头的end-user的值为jason,则将流量路由到reviews服务的v2版本上,其他流量路由在v1版
vs配置中的关键配置项
-
hosts:表示流量发送的目标(
可以理解为拦截目标,也可以理解为配置的路由规则归属哪一个Sidecar
),在k8s中hosts需要配置为服务的service域名,同namesapce下可以配置 短域名(因为可以跨namespace配置路由规则,所以这里是不便于管理的,如果重新开发istio配置管理dashboard可以考虑为域名分配增加权限
) -
http: 是一个类似httpRoute的路由集合,用于处理http的流量,是istio最丰富的的流量规则
-
tls:是一个tlsRoute类型的路由集合,用于处理非终结的tls和https流量
-
tcp:是一个tcpRoute类型的路由集合,用于处理tcp流量,应用于所有非http和tls端口的流量
-
exportTo:是istio在1.1版本后的新增特性,用于控制VS跨namespace的可见性。可以控制在一个命名空间下定义的vs是否可以被其他命名空间的Sidecar和Gateway使用。不填写代表全局可见,".“代表仅当前namespace可见,”* "代表所有namespace可见。
HttpRoute
在正常使用时,http协议的路由应用场景最多,主要介绍一下http路由的使用场景和使用方法
如上图,httproute可以通过请求中的内容为条件,对请求进行重定向、重写、重试、故障注入、流量复制等操作
我们把这些步骤拆分一下,主要分为匹配规则,重定向,重写,重试,故障注入,流量复制这几个方面来详述。
HTTPRoute的匹配规则
简述:匹配规则是分发流量的重要条件,关键字段是match字段,在match字段下就是对请求路由的匹配方式。
-
uri、scheme、method、authority:这4个字段都是StringMatch类型,请求规则中都支持exact(完全匹配),prefix(前缀匹配)、regex(正则匹配)三种匹配方式
-
headers:匹配请求中的header,是一个map类型,所以匹配时以k-v的形式比对,对每一个header的值都可以使用exact,prefix、regex三种匹配方式。
例:
- match:
- headers:
end-user:
exact: jason
uri:
prefix: "/testPipeline"
以上规则中包含了1和2的使用方式,代表匹配请求头中的end-user的值为jason且uri以/testPipeline开头的请求。
- port:表示请求的端口,在使用时大部分的服务都只开放了一个端口,在这种场景下可以不用指定端口(port在实际使用中使用率会小些)
- sourceLabels:表示请求来源服务的标签,在k8s中这个标签就是指pod的标签。
例:
http:
- match:
- sourceLabels:
app: cicdfront
version: v1.0.10
route:
- destination:
host: cicdapi
subset: v1.0.10
- route:
- destination:
host: cicdapi
subset: v1.0.9
当请求服务来源为cicdfront且其pod版本为v1.0.10时会将流量转发到cicdapi的v1.0.10上,其他的请求会发送到cicdapi的v1.0.9版本上
1.HttpRoute的路由目标
简述:路由目标代表请求流量发送到的目标服务,关键字段是route,在match(匹配规则)下时常代表匹配规则后的发送请求的目标服务。
当请求完成匹配规则后,我们需要对匹配到的请求进行转发,我们还是以开始的配置举例(稍微改动一下)。
http:
- match:
- headers:
end-user:
exact: jason
route:
- destination:
host: reviews
subset: v2
weight: 30
- destination:
host: reviews
subset: v3
weight: 70
- route:
- destination:
host: reviews
subset: v1
通过上节的匹配规则我们可以理解match中的匹配规则为请求头中的end-user的值为jason。当匹配这一条件时route路由生效,将请求的30%发送到reviews服务的v2版本上,另外70%发送到reviews服务的v3版本上。对未能匹配的请求路由到v1版本上。
这一转发需要搭配istio的另一个重要配置DR(DestinationRule)使用,DR种通过标签定义不同的pod服务。通过subset子集来完成请求的调用,这里按reviews服务的v1 v2两个pod理解就好。
- destination中的host与http中的host一致,在k8s中也是指向的service的域名,可以省略部分内容做短域名(在同namespace下的时候)。subset代表对应的dr子集。
- weight: 除了destination之外的另一个重要属性主要用于流量分配的比例,在一个route下多个dr下流量权重之和必须为100
2.HTTPRedirect重定向
简述:istio可以人工注入一些不可见的重定向规则,自定义的重定向规则在redirect关键字下。
理解了istio的vs工作模式那么我们接下来继续看istio的重定向功能,比较常见的使用场景:网站系统的网站地址发生了变化(并非服务器变化,只是访问地址的请求后缀变化
),要求使用之前的访问地址也能够进入网站,不影响旧用户的操作。这种情况下就很适合使用istio的重定向功能
- uri: 替换url中的path部分
- authority: 替换url中的authority部分
例:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: cicdapi
spec:
hosts:
- cicdapi
http:
- match:
- uri:
prefix: /pipeline
redirect:
uri: /cicd/pipeline
authority: newcicd
以上的请求对cicdapi服务的/pipeline请求都会被重定向到newcicd服务的/cicd/pipeline上
3.HTTPRewrite重写
简述:istio可以在请求发送给目标服务之前对请求信息进行改写,这个改写过程是对客户端及服务端都不可见的。重写与重定向很像。
关键字:rewrite
- uri: 重写url中的path部分
- authority: 重写url中的authority部分
例:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: cicdapi
spec:
hosts:
- cicdapi
http:
- match:
- uri:
prefix: /pipeline
rewrite:
uri: /cicd/pipeline
4.HTTPRerty重试
简述:很多时候http请求发生异常,重试都是解决异常的最直接,最简单的办法,尤其是环境比较复杂的情况下,可以提高总体的服务质量,但是这个重试逻辑如果放在客户端进行调度就过于不规范,不便于管理。istio可以支持这种重试的自动调度。
关键字:retry
- attempts:必填字段,定义重试的次数
- perTryTimeout:每次充实的超时时间,单位可以是毫秒(ms),秒(s),分钟(m)和小时(h)
- retryOn: 重试的条件,可以是多个条件以逗号分隔。可用条件有以下内容
(1)5xx:在上游服务返回5xx的返回码,或在没有响应的时候进行重试
(2)gateway-error:类似5xx异常,只对502,503,504的路由异常进行重试
(3) connect-failure:在连接上游服务失败时重试
(4)retriable-4xx:在上游服务返回可充实的4xx返回码时进行重试(这里可能不包括部分返回码,如404,405
)
(5)refused-stream:在上游服务使用REFUSED_STREAM错误码重置时重试
(6)cancelled:在gRPC应答的Header中状态码是cancelled时重试
(7)deadline-exceeded:在gRPC应答的Header中的状态码是deadline-exceeded时重试
(8)internal:在gRPC应答的Header中的状态码是internal时重试
(9)resource-exhausted:在gRPC应答的Header中的状态码是resource-exhausted时重试
(10)unavailable:在gRPC应答的Header中的状态码是unavailable时重试
例:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: cicdapi
spec:
hosts:
- cicdapi
http:
- route:
- destination:
host: cicdapi
retries:
attempts: 5
perTryTimeout: 3s
retryOn: 5xx,connect-failure
5.Mirror流量复制
简述:流量复制是指在流量需要发送到某个服务时,将这个请求流量复制一份到一个指定的服务上,如下图。可以将生产系统的流量复制到一个需要更新的新版本服务上,这样完全不会对生产系统产生影响,这里只复制了一份流量,数据面代理只需要住原来的流量就可以了。
关键字:mirror
例:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: portal-web
spec:
hosts:
- portal-web
http:
- route:
- destination:
host: portal-web
subset: v1.0.15
mirror:
host: portal-web
subset: v1.0.16
6.HttpFaultInjection故障注入
简述:除了转发重试这些常用的http请求操作,istio还支持故障注入。主要用于测试时主动模拟一些异常场景,比如跨服务请求超时,访问中发生错误等情况。
在istio中故障注入主要分为两种
- 延迟故障注入
延迟故障注入用来模拟超时的场景,模拟网络负载等原因导致的请求失败
配置参数如下:
(1)fixedDelay:必选字段,表示延迟的时间,单位可以是毫秒,秒,分钟,小时。要求时间必须大于1毫秒
(2)percentage:选填字段,配置故障发生的比例,通过这个配置可以配置故障发生的比例(无单位,支持小数,表示百分比。如果不填默认为100,注入所有请求)。
例:
……
- route:
- destination:
host: portal-web
subset: v1.0.15
- fault:
delay:
percentage:
value: 1.5
fixedDelay: 10s
表示对portal-web服务的请求的百分之1.5会被注入10s的延迟
- 请求中止故障注入
请求中止故障注入,主要是为了模拟服务端故障的情况,可以注入指定的返回码和返回信息
配置参数如下:
(1)httpStatus:是一个必选字段,表示中止的HTTP状态码
(2)percentage:配置的中止故障作用在多少比例的请求上,配置方式与延迟故障的一致。
例:
……
- route:
- destination:
host: portal-web
subset: v1.0.15
- fault:
delay:
percentage:
value: 1.5
httpStatus: 500
对portal-web服务的请求的百分之1.5会被模拟返回500的异常。
其实当了解了vs的大部分功能之后,我们可以看到vs的作用其实与k8s的service的作用基本是一致的,只是vs是用来修饰service的服务,可以调整、组合、拼接service,将多个service拼装成一个大的,富有规则的service。
DestinationRule目标规则
在我们刚刚查看VirtualService时候经常能看到这样一段配置
- route:
- destination:
host: portal-web
subset: v1.0.15
之前说这段配置指的是将流量发送给portal-web的v1.0.15的版本,这样说是为了方便理解。实际上这种说法是不严谨的,这段配置真实代表的含义是将请求转发给portal-web服务的destinationRule的v1.0.15的子集。
DestinationRule配置样例:
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: cicdpai
spec:
host: cicdapi
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
- name: v3
labels:
version: v3
DestinationRule规则定义
destinationRule经常与virtualService一起使用(dr是配合vs一起使用的,但是vs并不要求一定需要使用dr,如果不使用dr,vs会直接使用service来负载调用对应的pod
),virtualService用来修饰满足什么条件后被哪个后端处理。而destinationRule描述的是这个请求到达某个后端后该怎么去处理。
简述:vs设置服务的访问规则,具体请求服务时的规则由dr来决定。
关键属性:
(1)host:必选字段,表示规则的使用对象,对应的也是k8s中的service。域名解析方式与之前的host配置一致。
(2)trafficPolicy:规则的内容定义,包括负载均衡,连接池策略,异常点检查等内容。
(3)exportTo:Istio 1.1版本后新增的特性,用于控制DestinationRule跨命名空间的可见性,这样就能控制在一个命名空间下定义的资源对象是否可以被其他命名空间下的Sidecar执行。如果不做赋值代表全命名空间都可见。支持“.”
代表当前命名空间可见。"*"
代表全命名空间可见。
(4)subsets:代表一个服务的子集,一般代表一个服务的版本,与vs结合使用。每个子集都是通过label来匹配对应的pod,在istio的使用要求中建议用户为每个pod分配app、version两个标签。所以subset一般以version来划分,但这并不是硬性限制。
1.负载均衡设置
简述:当subset中可以匹配到多个pod时可以通过istio自身的负载均衡策略将请求分配。
- ROUND_ROBIN:轮循算法,如果设置了dr但没有为subset设置负载策略,那么会默认使用这个策略
- LEAST_CONN:最少连接算法,算法实现的是从两个随机选择的后端服务中选择一个链接数最少的链接
- RANDOM:完全随机策略,从现有的健康可用的后端服务中随机抽取一个地址
- PASSTHROUGH:直接转发到客户端链接的目标地址,不做转发(这样会有k8s的service进行负载)
2.连接池设置
简述:通过连接池管理可以配置阈值来放置一个服务的失败影响到整个应用。istio的连接池可以配置tcp流量、http流量治理
- tcp连接池配置(TCPSetting):
(1)maxConnections:表示为上有服务的所有实例的最大连接数,默认为1024.对于HTTP只适用于HTTP/1.1因为HTTP/2对每个主机都使用单个连接。
(2)connectTimeout:TCP连接超时时间。
(3)tcpKeeplive:是Istio1.1版本后新增的特性,定期给对端发送一个keepalive的探测包,判断连接是否可用。包含三个属性–probes(标识有多少次探测没有反应就判断连接断开,默认使用操作系统的默认配置,linux默认为9),time(标识发送探测前连接空闲了多少时间,也是用操作系统的默认配置,linux默认为2小时),interval(探测间隔,也是用操作系统的默认配置,linux默认为75秒)。 - http连接池配置(HTTPSetting):
(1)http1MaxPendingRequests:最大等待HTTP请求数,默认值为1024,只适用于HTTP/1.1,因为HTTP/2协议的请求在到来时会立即复用连接,不会再连接池等待
(2)http2MaxRequests:最大请求数,默认1024。只适用于HTTP/2服务,因为HTTP/1.1适用最大连接数配置maxConnections即可。
(3)maxRequestsPerConnection:每个连接的最大请求数。如果不配置则不作限制
(4)maxRetries:最大重试次数,默认为3,表示服务可以执行的最大重试次数。如果调用后端因网络抖动导致调用失败,可能会带来业务损失,一般建议配置重试,若重试成功则可以正常配置返回数据,只不过比原来响应的时间稍慢一点。但重试次数过多会对性能产生影响,尽量不要对消耗大的服务进行重试。
(5)idleTimeout:空闲超时,定义在多长时间内没有活动请求则关闭连接。
3.异常实例检测设置
简述:异常点检查就是定期考察被访问的服务实例的工作情况,如果连续出现访问异常,则将服务实例标记为异常并进行隔离,在一段时间内不为其分配流量,过一段时间被移除的实例会被解除移除,尝试请求,如果访问失败会进行更长实际胺的隔离,这也是istio的熔断功能。
参数配置:
- consecutiveErrors:实例被驱逐前的
连续
错误次数,默认为5,对于http服务返回502,503,504的返回码会认为服务异常。 - interval:驱逐检查的时间间隔(驱逐检测的统计时间),默认为10秒,要求大于1毫秒,单位可以是时、分、毫秒
- baseEjectionTime:最小驱逐时间。一个服务被驱逐的时间等于驱逐次数乘以最小驱逐时间。所以被驱逐的实例再被再次驱逐时会变得越来越长。时间默认为30秒,要求大于1毫秒,单位可以是时、分、毫秒。
- maxEjectionPercent:服务的可驱逐故障实例的最大比例,默认为10%。官方不建议配置过高,过分的驱逐会影响服务的服务能力
- minHealthPercent:最小健康比例,是istio 1.1版本后新增的特性,当负载的实例中,如果健康的实例数量低于这个比例,istio会进入恐慌模式,异常检查功能会被禁用,所有的服务不论是否是故障实例都可以接受请求。
例:
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: cicdapi
namespace: paas
spec:
host: cicdapi
trafficPolicy:
connectionPool:
tcp:
maxConnections: 80
connectTimeout: 25ms
http:
http2MaxRequest: 800
maxRequestsPerConnection: 10
outlierDetection:
consecutiveErrors: 5
interval: 4m
baseEjectionTime: 10m
maxEjectionPercent: 30
检查4分钟内cicdapi服务的异常情况,连续出现5次连接异常的服务实例会被隔离10分钟,被隔离的服务数量不能超过30%。达到十分钟后实例会重新接受请求,如果依然不能正常工作会被隔离20分钟
5.端口策略
简述:当我们熟悉以上的连接池配置后,实际端口配置也没有什么特殊的地方,实际上就是为了某些端口配置一些特殊规则,比如最大连接数等
例:
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: cicdapi
namespace: paas
spec:
host: cicdapi
trafficPolicy:
connectionPool:
tcp:
maxConnections: 80
portLevelSettings:
- port:
number: 8081
connectionPool:
tcp:
maxConnections: 100
cicd服务的最大连接数为80,但8081端口单独配置了最大连接数为100
6.服务子集
简述:subset主要作用就是通过label标签配置真实的后端服务。virtualService中通过制定subset的name来引用对应的服务。
name:必选字段,subset的名字,通过virtualService引用subset的时候就是通过name来引用的
labels:服务标签,通过标签来引用真实的后端服务,最常用的标签为version标签
trafficPolicy:应用到这个subset的流量策略
例:
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: cicdapi
namespace: paas
spec:
host: cicdapi
subset:
- name: v2
labels:
version: v2
trafficPolicy:
connectionPool:
tcp:
maxConnections: 80
dr的作用主要就是配置目标服务的匹配方式和负载均衡、熔断的服务治理方式。
Gateway服务网关
之前的配置不论是vs还是dr的配置都是针对服务间的访问做的样例,没有针对过外部请求访问容器服务的样例。这种请求都需要通过istio的服务网关来配置。
样例:
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: cicdfront-gateway
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "cicdfront.com"
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: cicd-front
spec:
hosts:
- frontend
- cicdfront.com
gateways:
- cicdfront-gateway
- mesh
http:
- route:
- destination:
host: cicd-front
port:
number: 8080
Gateway规则定义
Gateway一般需要与virtualService结合使用,Gateway定义了服务从外面怎么访问,virtualService定义了匹配到内部服务怎么流转。
关键配置:
selector:必选字段,表示Gateway负载,为入口处的Envoy运行的pod标签
server:必选字段,表示开放的服务列表
后端服务Server
简述:server定义了服务的访问入口
- port:必选字段,描述了服务在哪个端口对外开放,是对外监听端口。
- hosts:必选字段,为Gateway发布的服务地址,是一个域名,用来匹配virtualService的hosts,会匹配到设置了同样hosts的vs。
例:
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "cicdfront.com"
ServiceEntry外部服务配置
简述:将网格外的服务加入网络中,像网格内的服务一样管理,实际上就是将不归属istio自动注入的服务加入到istio的服务发现。
配置示例
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: cicdfront-entry
spec:
hosts:
- www.cicddb.com
ports:
- number: 80
name: http
protocol: HTTP
resolution: DNS
location: MESH_EXTERNAL
ServiceEntry规则定义
重要参数:
- hosts:必选字段,表示ServiceEntry相关的主机名,可以是一个DNS域名,可以使用前缀模糊匹配
- addresses:表示与服务关联的虚拟IP地址。
- port:表示与外部服务关联的端口。
- location:设置服务时在网格内还是网格外,支持以下两种模式
(1)MESH_EXTERNAL:表示在网格外部,通过api访问的外部服务。
(2)MESH_INTERNAL:表示在网格内部,一些不能直接注册到服务网格注册中心的服务。 - resolution: 表示服务的发现模式,将服务名解析到一个后端的IP上。可以设置NONE、STATIC、DNS三种模式
(1)NONE:用于连接的目标地址已经是一个明确的IP场景是使用。
(2)STATIC:用在已经使用endpoint设置了服务示例的地址场景中, 也不需要解析。
(3)DNS:表示用查询环境中的DNS进行解析,前提是没有在hosts中使用通配符。 - subjectAltNames: 表示这个服务负载的SAN列表
- endpoints:表示与网格服务关联的网络地址,可以是一个IP,可以是一个主机名。endpoints通过很多字段一同生成
(1)address: 必选字段,表示网络后端的服务地址
(2)ports:端口列表
(3)labels:后端的标签
(4)locality:后端的locality,用于亲和性路由
(5)weight:表示负载均衡的权重。
END
- 我们在正常使用中,多使用的一般只有virtualService,destinationRule、Gateway这三种功能。vs负责配置访问规则、dr负责配置目标实例和负载规则,Gateway负责配置入口规则。配置好这三种配置就可以满足我们大部分的使用场景。
但在使用中会发现这几种问题
- istio基本所有的功能配置时都要求一个必填字段
hosts
,在k8s集群中 ,这个hosts是我们服务的长短域名,也就是service的名称。所以在很大程度来讲,istio都是基于service在工作。但是istio没有图形界面提供功能配置,不论是vs,dr,gw都是需要通过yaml配置的。这种配置就不能限制用户的一些误操作,比如对一个服务配置误配置了两个vs,那么哪个会是有效的vs?对一个服务配置了两个dr,那么哪个会是有效的dr?前面提过istio在1.1版本之后新增了exportTo属性,代表当前配置能否支持跨namespace,默认都是允许跨namespace生效的,这样会不会出现误引用的情况?
所以在使用时还是建议封装istio的yaml拼装功能,通过页面进行控制,防止误配置yaml。
-
istio会进行服务间的流量治理,实现方式是通过iptables进行流量拦截,这样使用时为了让入口服务也能被istio治理就必须使用istio的入口网关Gateway。这样平台使用时就不能直接为用户提供route的方式访问平台。需要使用gateway进行包装才行。但并不是所有服务都需要进行包装,只有需要在集群外直接访问的服务需要进行这个包装。(
大部分都是前台服务才需要进行这个步骤:浏览器 --> cicd-front --> cicd-api,这种情况下就需要为cicdfront生成入口网关,用户需要通过入口网关访问cicdfront才能治理这部分流量
) -
集群内不能直接访问集群外的url