Overview
这篇介绍在Istio中流量管理如何工作,包括流量管理原则的优势。假设你已经读过What is Istio并熟悉Istio的高级架构。
Pilot and Envoy
在Istio中,流量管理的核心组件使Pilot,它管理和配置部署在Istio服务网格中的所有Envoy代理实例。它让你指定Envoy代理之间路由流量所使用的规则,配置故障恢复功能,如超时、重试、熔断。它也维护了一个在网格中所有服务的标准模型,并使用它来让Envoy通过其发现服务了解网格中的其他实例。
每个Envoy实例基于从Pilot获得的信息来维护负载均衡信息,并定期对它的负载均衡池中的其他实例进行健康检查,使它按照指定的路由规则在目标实例间智能分配流量。
Traffic management benefits
使用Istio流量管理模型本质上解耦了流量和基础架构扩展,让运维通过Pilot指定它们希望流量遵循哪些规则,而不是哪些特定的pods/VMs接受流量——Pilot 和 智能Envoy代理负责监控其余部分。例如,你可以通过Pilot指定你希望某个特定服务的5%流量进入金丝雀版本,而无需考虑金丝雀部署的大小;或者根据请求的内容将流量发送到特定版本。
像这样从基础架构解耦流量允许Istio在应用代码外部提供流量管理功能。除了A/B测试,滚动发布和金丝雀部署的动态请求路由,它还使用超时、重试、熔断来处理故障恢复,最后进行故障注入以测试跨服务的故障恢复策略的兼容性。这些功能都是通过在服务网格中部署Envoy sidecar/proxies来实现的。
Pilot
Pilot负责跨Istio服务网格部署的Envoy实例的生命周期。
如上图,Pilot维护独立与底层平台的网格中的服务的规范表示。Pilot中的特定平台适配器负责适当填充此规范模型。比如,Pilot中的k8s适配器实现必要的控制器,以观察k8s API server中更改的pod注册信息、入口资源和存储流量管理规则的第三方资源。这些数据被转换为规范表示。指定Envoy的配置是基于规范表示生成的。
Pilot公开了用于服务发现、动态更新负载均衡池和路由表的API。这些API将Envoy和特定平台的细微差别解耦,简化了设计并提高了跨平台的可移植性。
运维可以通过Pilot的规则API指定高级流量管理规则。这些规则被转换为低级配置,并通过发现API分发给Envoy实例。
Request Routing
这篇介绍Istio服务网格中的服务间请求如何路由。
Service model and service versions
如在Pilot中的描述,Pilot维护特定网格中服务的规范表示。服务的Istio模型与其所在底层平台(Kubernetes, Mesos, Cloud Foundry, etc.)中的表现方式无关。特定平台适配器负责使用在平台中找到的元数据中的各个字段来填充内部模型表示。
Istio引入了服务版本的概念,它按版本 (v1
, v2
) 或环境(staging
, prod
)细分服务实例的实现细粒度划分。这些变体不一定是不同的API版本:他们可能是对同一服务进行迭代更改,然后部署在不同环境中(prod, staging, dev, etc.)。常用场景包括A/B测试或金丝雀发布。Istio的流量路由规则可以指定服务版本,以提供对服务间流量的额外控制。
Communication between services
如上图,服务客户端不需知道服务的不同版本。 它们可以通过服务的hostname/IP地址持续访问服务。Envoy sidecar/proxy拦截并转发客户端和服务之间的所有请求/响应。
Envoy根据运维使用Pilot指定的路由规则动态选择实际服务的版本。该模型使应用代码与其相关服务的演进解耦,同时提供了其他好处(见Mixer)。路由规则使Envoy根据标准选择版本,这些标准形如headers、与源/目标相关的标签、分配给每个版本的权重。
Istio同时为流量提供相同服务版本的多个实例的负载均衡。在Discovery and Load-Balancing产看更多。
Istio不提供DNS解析。应用可以尝试使用依赖平台使用的DNS服务 (kube-dns, mesos-dns, etc.)解析FQDN。
Ingress and egress
Istio假设所有进出服务网格的流量都通过Envoy进行中转。通过在服务之前部署Envoy代理,运维可以进行A/B测试,金丝雀部署等面向用户的服务。同时,依托Envoy sidecar,通过路由外部web服务(如一个Maps API或video API),运维可以加入故障恢复功能,如超时、重试、熔断等,并通过这些服务的通信获取具体的metrics。
Discovery & Load Balancing
这篇介绍Istio如何在服务网格中负载均衡服务实例间的流量。
Service registration: Istio假定服务注册表存在,以追踪pods/VMs上的应用中的服务。它还假定服务的新实例会自动注册,不健康实例会自动删除。如k8s、Mesos等平台已经为基于容器的应用提供了这样的功能。基于VM的应用存在大量解决方案。
Service Discovery: Pilot使用来自服务注册中心的信息,并提供平台无关的服务发现界面。网格中Envoy实例执行服务发现,并相应地动态更新其负载均衡池。
如上图,网格中的服务通过使用它们的DNS名访问彼此。绑定到服务的所有HTTP流量都会通过Envoy自动重新路由。Envoy在负载均衡池中的实例间分配流量。尽管Envoy支持多种复杂的负载均衡算法,但是Istio目前只支持三种:轮询,随机和加权最少请求。
除了负载均衡,Envoy还会定期检查池中每个实例的健康状况。Envoy遵循断路器模式,根据健康检查API调用的故障率划分实例为不健康或健康的。换句话说,当给定实例的运行检查失败次数超过预先设定的阈值时,它将从负载均衡池中被清除。同样,当传递的运行状态健康检查数超过预先设定阈值时,它将被添加回负载均衡池。可以在Handling Failures了解更多Envoy故障处理能力。
服务可以通过HTTP 503的响应健康检查来积极地减轻负载。在这种情况下,服务实例将立即从调用者的负载均衡池中移除。
Handling Failures
Envoy提供一套开箱即用的选择性故障恢复功能,可以在应用中更好的使用服务。功能包括:
1. 超时
2. 带有超时预算的有界重试和重试间变量抖动
3. 并发连接数和上游服务请求的限制
4. 对负载均衡池中的每个成员主动(定期)健康检查
5. 细粒度熔断(被动健康检查)—— 针对负载均衡池中的每个实例
这些功能可以通过Istio的traffic management rules在运行期动态配置。
重试间的抖动最小化了重试对上游服务重载的影响,而超时预算确保呼叫服务在可预测时间范围内获得响应(成功/失败)。
主动和被动的健康检查组合(上述4和5)可最大限度减少访问负载均衡池中不健康实例的机会。当与平台级健康检查结合时(如k8s或Mesos支持的),应用可以确保不健康的pods/容器/VMs能快速从服务网格中清除,最大限度减少请求失败和延迟的影响。
这些功能一同使服务网格能够容忍失败节点,防止由于级联不稳定导致的本地失败影响到其他节点。
Fine tuning
Istio流量管理规则使运维为每个服务/版本的故障恢复设置全局默认值。然而,自定义服务可以通过特定HTTP 请求头中提供请求级覆盖去覆写超时和重试默认值。Envoy代理中,请求头分别时是 “x-envoy-upstream-rq-timeout-ms” 和“x-envoy-max-retries”。
FAQ
运行在Istio中的应用还需要处理故障吗?
当然。Istio在网格中提供高可用服务。但是,应用需要处理故障,并采取恰当的fallback方法。例如,当负载均衡池中的所有实例失败了,Envoy会返回HTTP 503.这表示应用需要在上游服务有处理HTTP 503错误码的fallback逻辑。Envoy的故障恢复功能会破坏应用已有的容灾库吗(如Hystrix)?
不。Envoy完全对应用透明。由Envoy返回的故障响应与进行调用的上游服务返回的故障响应没什么不同。当同时使用Envoy和应用级库处理故障时会发生什么?
为同一目标服务提供两个故障恢复策略(如两个超时——一个是Envoy,另一个是应用级库),当故障发生时,会触发二者中更严格的那个。例如,如果应用对一个服务的API调用设置5s超时,运维配置10s超时,则应用的超时首先启动。同样,如果Envoy的熔断在应用的熔断之前触发,服务的API调用从Envoy返回503.
Fault Injection
尽管Envoy sidecar/proxy为运行在Istio上的服务提供了很多故障恢复机制,测试整个应用的端到端故障恢复能力仍然是必要的。错误配置的故障恢复策略(如跨服务调用的不兼容/限制性超时)可能导致应用中的关键服务不可用,从而导致用户体验极差。
Istio支持将特定协议故障注入网络,而不是杀死pods、延迟或破坏TCP层的数据包。我们的依据是应用层观察到的故障应该是相同的,和网络级的失败无关;并且可以在应用层注入更多有意义的失败(如HTTP错误码)来锻炼应用的恢复能力。
运维可以配置故障注入到符合特定标准的请求中。运维可以进一步限制应该发生故障的请求的百分比。可以注入两种类型故障:delays and aborts。Delays是定时失败、模仿网络延迟增加或上游服务超负荷。Aborts是模仿上游服务故障导致的崩溃。Aborts通常以HTTP错误码或TCP连接失败的形式出现。
在Istio的traffic management rules发现更多。
Rules Configuration(0.7)
Istio提供一个简单的特定领域语言(DSL)去控制如何调用API及应用部署中跨不同服务的第四层流量。DSL允许运维配置服务级属性,如熔断,超时,重试,以及建立常见的持续部署任务,如金丝雀发布,A/B测试,基于%流量分组的分阶段发布等。更多详见here
例如,如下是一个使用DSL规则描述的将“reviews”服务的传入流量100%发送到“v1”版本的简单规则:
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: reviews-default
spec:
destination:
name: reviews
route:
- labels:
version: v1
weight: 100
destination是被路由流量的服务名。route 的labels确定接受流量的特定服务实例。例如,Istio的k8s部署中,route的labels为“version:v1”表明只有包含标签“version:v1”的pods能接受流量。
规则可以使用istioctl CLI配置,或使用k8s部署的kubectl命令。查看configuring request routing task。
在Istio中由三种流量管理策略:Route Rules, Destination Policies(和Mixer policies不同),及Egress Rules。三种规则都控制请求如何路由到目标服务。
Route Rules
Route Rules控制Istio服务网格如何路由请求。例如,一个路由规则可以路由请求到一个服务的不同版本。请求可以根据源和目标、HTTP请求头字段、各服务版本相关权重进行路由。编写路由规则时,必须牢记以下几个方面:
Qualify rules by destination
每个规则对应于规则中的destination字段标识的目标服务。例如,申请调用“reviews”服务的规则通常至少包含如下内容。
destination:
name: reviews
destination值显示或隐式的指定一个全限定名(FQDN)。被用于Istio Pilot按规则匹配服务。
通常服务的全限定名由三部分组成:name, namespace, and domain
FQDN = name + "." + namespace + "." + domain
这些字段如下显示指定。
destination:
name: reviews
namespace: default
domain: svc.cluster.local
更常见的是,为了简化和最大限度的重用规则(如在多个命名空间或域中使用相同规则),规则destination仅指定name字段,依赖于其他两个默认值。
namespace的默认值是规则自己所属命名空间,可能在规则的metadata字段中指定,或在使用命令istioctl -n <namespace> create
或 kubectl -n <namespace> create
安装rule时指定。domain的默认值时特定实现的。如在k8s中,默认值是svc.cluster.local
。
有时候,比如在egress rules或在namespace和domain无意义的平台上涉及外部服务时,使用可替代字段service来明确指定目的地。
destination:
service: my-service.com
当service字段被指定,其他字段的显示或隐式值将被忽略。
Qualify rules by source/headers
规则可选择性的限定为仅适用于匹配某些特定条件的请求,如下:
1. 限制特定调用者。例如,下述规则仅允许“reviews”服务调用。
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: reviews-to-ratings
spec:
destination:
name: ratings
match:
source:
name: reviews
...
source值,就像destination值,显示或隐式地指定一个服务的FQDN。
2. 限定调用者的特定版本。例如,下属规则细化之前的例子,仅允许“v2”版本的“reviews”服务调用。
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: reviews-v2-to-ratings
spec:
destination:
name: ratings
match:
source:
name: reviews
labels:
version: v2
...
3. 基于HTTP请求头选择规则。例如,下属规则仅允许cookie中包含“user=jason”的请求进入。
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: ratings-jason
spec:
destination:
name: reviews
match:
request:
headers:
cookie:
regex: "^(.*?;)?(user=jason)(;.*)?$"
...
如果提供了多个header,则必须匹配所有的headers,规则才能适用。
可以同时设置多个标准。这种情况下,应用AND语法。如下属规则仅允许源请求是 “reviews:v2” AND 当前cookie中包含“user=jason”。
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: ratings-reviews-jason
spec:
destination:
name: ratings
match:
source:
name: reviews
labels:
version: v2
request:
headers:
cookie:
regex: "^(.*?;)?(user=jason)(;.*)?$"
...
Split traffic between service versions
每条路由规则标识一个或多个加权后端,以便在规则激活时进行调用。每个后端对应于目标服务的特定版本,其中可以使用labels表示版本。
如果有多个具有指定标签的注册实例时,它们将根据为服务配置的负载均衡策略进行路由,或者使用默认循环策略。
例如,如下规则路由25%的流量到“v2”标签的“reviews”服务实例,剩下的流量路由到“v1”。
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: reviews-v2-rollout
spec:
destination:
name: reviews
route:
- labels:
version: v2
weight: 25
- labels:
version: v1
weight: 75
Timeouts and retries
http请求的默认超时为15s,但可以被如下路由规则覆盖:
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: ratings-timeout
spec:
destination:
name: ratings
route:
- labels:
version: v1
httpReqTimeout:
simpleTimeout:
timeout: 10s
给定http请求的重试次数也可以在路由规则中指定。最大尝试次数,或者在默认或重写的超时时限内尽可能多的尝试,可以像如下设置:
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: ratings-retry
spec:
destination:
name: ratings
route:
- labels:
version: v1
httpReqRetries:
simpleRetry:
attempts: 3
注意请求超时或重试也可以被每个请求重写。
在 request timeouts task有超时控制的示范。
Injecting faults in the request path
路由规则可以指定一个或多个故障注入,同时将http请求转发到规则对应的请求目标。故障可能是延迟或中止。
以下例子将在“reviews”微服务的”v1“版本中的10%请求引入5s延迟。
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: ratings-delay
spec:
destination:
name: reviews
route:
- labels:
version: v1
httpFault:
delay:
percent: 10
fixedDelay: 5s
另一种故障,中止,可用于过早终止请求,例如模拟故障。
下述例子将在”ratings“服务的“v1”版本中的10%请求返回HTTP 400错误码。
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: ratings-abort
spec:
destination:
name: ratings
route:
- labels:
version: v1
httpFault:
abort:
percent: 10
httpStatus: 400
有时延迟和中止同时使用。如,下面例子将对从“reviews”的“v2”服务到“ratings”的“”v1服务的所有请求延迟5s,然后终止其中10%的请求:
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: ratings-delay-abort
spec:
destination:
name: ratings
match:
source:
name: reviews
labels:
version: v2
route:
- labels:
version: v1
httpFault:
delay:
fixedDelay: 5s
abort:
percent: 10
httpStatus: 400
查看action中的失败注入,查看 fault injection task
Rules have precedence
多重路由规则可以应用到相同目标。通过设定规则precedence字段,可以指定目标对应的多个规则的评估顺序。
destination:
name: reviews
precedence: 1
precedence字段是一个可选整数值,默认为0。precedence值越高,规则的评估越靠前。如果多个规则有相同的precedence,那么评估的顺序不定。
什么时候优先级有用?每当某个特定服务的路由纯粹基于权重时,就可以在每个规则中指定它,就像前面的例子。另一方面,当其他方面(如来自特殊用户的请求)用于路由流量时,需要多个规则来指定路由。这时就必须设置precedence来确保规则能够按正确顺序被评估。
通用路由规范的一个常见模式是提供一个或多个更高优先级的规则,将规则的source/headers限定到特定目标,然后以最低优先级提供没有匹配标准的单个基于权重的规则,来为所有其他情况提供流量的加权分布。
例如,如下两个规则一起指定header中包含键值对Foo: bar所有请求发送到“reviews”的“v2”版本实例,剩下的请求发送到“v1”中。
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: reviews-foo-bar
spec:
destination:
name: reviews
precedence: 2
match:
request:
headers:
Foo: bar
route:
- labels:
version: v2
---
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: reviews-default
spec:
destination:
name: reviews
precedence: 1
route:
- labels:
version: v1
weight: 100
注意到基于header的规则有更高的优先级(2 vs 1).如果它的优先级更低,则这些规则由于基于权重,没有特定匹配条件,将不能按预期工作,由于“v1”先被评估,所以所有流量都将路由到“v1”中,即使请求中包含匹配的“Foo” header。一旦规则能适用进入的请求,它将会执行,规则评估过程将会终止。这也是为何超过一个规则时,仔细的考虑规则优先级时非常重要的。
Destination policies
目标策略描述了与特定服务或版本相关的各种路由相关策略,如负载均衡算法,熔断配置,健康检查等。
不同于路由规则,目标策略只能由呼叫服务的请求的属性来限定,但它们可以被限制为适用于使用特定标签路由到目标后端的请求。例如,下面的负载均衡策略仅适用被“reviews”的“v2”版本调用,目标为“ratings”的“v1”版本的请求。
apiVersion: config.istio.io/v1alpha2
kind: DestinationPolicy
metadata:
name: ratings-lb-policy
spec:
source:
name: reviews
labels:
version: v2
destination:
name: ratings
labels:
version: v1
loadBalancing:
name: ROUND_ROBIN
Circuit breakers
一个简单的熔断可以根据很多标准设置,如连接和请求限制。
如下目标策略设置了“reviews”的“v1”后端服务最大连接为100.
apiVersion: config.istio.io/v1alpha2
kind: DestinationPolicy
metadata:
name: reviews-v1-cb
spec:
destination:
name: reviews
labels:
version: v1
circuitBreaker:
simpleCb:
maxConnections: 100
完整的简单熔断字段在 here。
Destination policy evaluation
和路由规则类似,目标策略也和特定destination有关,但如果它们也包含labels,则其激活取决于路由规则的评估结果。
规则评估过程的第一步是评估destination的路由规则(如果有定义),以确定当前请求将路由到目标服务的标签(即特定版本)。然后,该组目标策略(如果有)会被评估以确定它们是否适用。
注意:记住算法的一个微妙之处在于,只有在相应的标记实例被明确路由到时,才会应用为特定标记的目标策略。如下,作为“reviews”服务定义的唯一规则。
apiVersion: config.istio.io/v1alpha2
kind: DestinationPolicy
metadata:
name: reviews-v1-cb
spec:
destination:
name: reviews
labels:
version: v1
circuitBreaker:
simpleCb:
maxConnections: 100
因为这里没有为“reviews”服务定义特定的路由规则,所以会适用默认的循环路由行为,在某些情况下将会调用“v1”实例,甚至“v1”总是唯一运行的版本。不过,由于默认路由是在较低级别完成的,因此不会调用上述策略。规则评估引擎不知道最终目标,因此无法将目标策略与请求匹配。
你可以通过如下两种方式修复上述例子。如果“v1”是唯一实例,你可以从规则中移除 labels:
;或者更好的方式是,为服务定义适当的路由规则,比如简单的为 “reviews:v1”加一个路由规则。
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: reviews-default
spec:
destination:
name: reviews
route:
- labels:
version: v1
虽然默认的Istio行为方便地将来自所有版本地源服务流量发送到目标服务地所有版本,并无需设置任何规则,但只要希望区分版本时,那么就需要规则。因此,一开始就为每项服务设置默认规则,通常被认为是Istio地最佳做法。
Egress Rules
出口规则用于适用Istio服务网格外的服务请求。如下规则,允许外部服务调用托管在 *.foo.com
域名下的服务。
apiVersion: config.istio.io/v1alpha2
kind: EgressRule
metadata:
name: foo-egress-rule
spec:
destination:
service: *.foo.com
ports:
- port: 80
protocol: http
- port: 443
protocol: https
出口规则的目标是适用service字段指定,该字段可能是完全限定的或通配的域名。它表示白名单中列出一个或多个外部服务允许访问网格中的服务。在 here查看通配符语法。
目前,只有基于HTTP的服务可以使用出口规则,然而,源于sidecar的TLS可以通过将关联的服务端口协议设置为“https”来实现,如上例所示。该服务必须通过HTTP访问(e.g., http://secure-service.foo.com:443
, instead of https://secure-service.foo.com
),不过,这种情况下,sidecar将升级为TLS连接。
只要它们使用与对应的出口规则完全相同的目标服务规范来引用外部服务,出口规则就可以很好的与路由规则和目标策略结合使用。例如,下述规则可以与上述出口规则结合使用,以设置对外服务调用的10s超时时间。
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: foo-timeout-rule
spec:
destination:
service: *.foo.com
httpReqTimeout:
simpleTimeout:
timeout: 10s
用于重定向和转发流量的目标策略和路由规则,来定义支持外部目标的重试、超时和故障注入策略。然而,由于没有多个外部服务版本的改变,加权(基于版本)路由不可能实现。
Rules Configuration(0.8)
Istio提供一个简单配置模型来控制在一个应用部署中如何通过调用API和4层流量访问各种服务。配置模型允许运维配置服务级的属性,例如熔断,超时,重试,以及设置常见的连续部署任务,如金丝雀发布,A/B测试,基于百分比流量切分的分期发布等。
例如,一个针对reviews 服务的“v1”版本发送100%入流量的路由规则可以用如下配置来描述:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
这个配置表示发送到reviews服务的流量(在hosts
字段指定)应该路由到基本的reviews服务实例的v1子集上。路由的subset
指定相应目标规则配置(上面的destination字段)中定义的子集名称:
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: reviews
spec:
host: reviews
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
subset指定一个或多个标识特定版本实例的标签。例如,在一个部署在k8s上的istio中,“version: v1”表示只有pods中包含“version: v1” 标签才会接受流量。
规则可以由istioctl CLI配置,也可以在k8s部署中使用kubectl
命令,但只有istioctl
将执行模型验证,并且推荐使用它。可以看 configuring request routing task 中的例子。
在Istio中有四个流量管理配置资源:VirtualService, DestinationRule, ServiceEntry, and Gateway. 下面介绍这些资源的几个重要方面。更多信息参见 networking reference .
Virtual Services
一个 VirtualService 定义了在istio服务网格中如何控制路由到一个服务的请求的规则。例如,一个虚拟服务能够路由请求到服务的不同版本,或者实际上可以将请求路由到完全不同于所请求的服务。路由请求基于请求源和目标,HTTP路径,header字段,以及关联服务不同版本的权重。
Rule destinations
在VirtualService
配置中,路由规则指定了一个或多个目标hosts。这些hosts可能与实际的目标工作负载相同,也可能不同,甚至可能不对应网格中的实际可路由服务。例如,为请求reviews服务使用它的内部网格名reviews
或者通过host bookinfo.com
定义路由,一个VirtualService
的 hosts
字段 可能类似这样:
hosts:
- reviews
- bookinfo.com
这个hosts
字段直接或间接地指定了一个或多个完全限定域名(FQDN)。上面的短名字reviews
间接地扩展到特定实现地FQDN。例如,在k8s环境中的VirtualSevice
全名由集群和命名空间推导而来(e.g., reviews.default.svc.cluster.local
)
Qualify rules by source/headers
规则可以选择性地限定为仅适用于匹配某些特定条件地请求,如下:
1.限制特定调用者。 例如,一个规则可以表明它仅适用于来自执行reviews服务地工作负载(pods)地调用。
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: ratings
spec:
hosts:
- ratings
http:
- match:
sourceLabels:
app: reviews
...
sourceLabels
的值依赖于服务的实现。例如在k8s中,它可能与相应的k8s服务的pod的selector中使用的标签相同。
2.限制调用者的特定版本。如下规则改善上面的例子,仅适用reviews服务的v2版本调用。
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: ratings
spec:
hosts:
- ratings
http:
- match:
- sourceLabels:
app: reviews
version: v2
...
3.基于HTTP请求头筛选规则。如下规则仅适用“cookie”头包含子串“user=jason”的入站请求。
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- match:
- headers:
cookie:
regex: "^(.*?;)?(user=jason)(;.*)?$"
...
如果提供了超过一个的header,那么必须所有对应的headers匹配才能应用这个规则。
可以同时设置多重标准。在这种情况下,根据嵌套,应用AND或OR语义。如果多重标准嵌套在一个匹配子句中,则条件为ANDed。如下规则仅适用于源请求是 “reviews:v2” AND “cookie” 头包含 “user=jason” 。
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: ratings
spec:
hosts:
- ratings
http:
- match:
- sourceLabels:
app: reviews
version: v2
headers:
cookie:
regex: "^(.*?;)?(user=jason)(;.*)?$"
...
相反,标准出现在分开的匹配子句中,仅有一个条件必须满足(OR语义):
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: ratings
spec:
hosts:
- ratings
http:
- match:
- sourceLabels:
app: reviews
version: v2
- headers:
cookie:
regex: "^(.*?;)?(user=jason)(;.*)?$"
...
(注意上面两个不同之处在于headers前面的-)
Split traffic between service versions
每个路由规则标识一个或多个加权后端,以便在规则激活时调用。每个后端对应于目标服务的特定版本,可以中labels表示版本。如果特定label有多个注册实例,他们会基于服务配置的负载均衡策略被路由到,或者默认使用循环。
例如,如下规则将路由reviews服务的25%流量到label为“v2”的实例,剩下的路由到“v1”.
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
weight: 75
- destination:
host: reviews
subset: v2
weight: 25
Timeouts and retries
默认http请求的超时时间是15s,但这可以在一个路由规则中被覆写,就像下面这样:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: ratings
spec:
hosts:
- ratings
http:
- route:
- destination:
host: ratings
subset: v1
timeout: 10s
对于一个给定http请求的重试次数也可以在一个路由规则中指定。在默认或重写的超时期限内,最大尝试次数或尽可能多的尝试次数可以设置如下:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: ratings
spec:
hosts:
- ratings
http:
- route:
- destination:
host: ratings
subset: v1
retries:
attempts: 3
perTryTimeout: 2s
注意,请求超时和重试同样能在每个请求的基础上被覆写(overridden on a per-request basis)
在 request timeouts task 可以看到一个控制超时的范例。
Injecting faults in the request path
一个路由规则能在http请求转发到规则的相应请求目标时指定一个或多个故障注入。故障可能是延时或中止。
下例将介绍对于ratings微服务的“v1”版本的10%的请求进行5s延时。
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: ratings
spec:
hosts:
- ratings
http:
- fault:
delay:
percent: 10
fixedDelay: 5s
route:
- destination:
host: ratings
subset: v1
另一种故障,中止,可以用来过早的中止请求,比如模仿失败。
下例将对ratings服务v1的10%的请求返回一个HTTP 400错误码。
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: ratings
spec:
hosts:
- ratings
http:
- fault:
abort:
percent: 10
httpStatus: 400
route:
- destination:
host: ratings
subset: v1
有时延迟和中止故障同时使用。例如,下例将对来自reviews服务v2版本到ratings服务v1版本的请求进行5s延时,并将其中的10%中止:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: ratings
spec:
hosts:
- ratings
http:
- match:
- sourceLabels:
app: reviews
version: v2
fault:
delay:
fixedDelay: 5s
abort:
percent: 10
httpStatus: 400
route:
- destination:
host: ratings
subset: v1
更多故障注入,可查看 fault injection task 。
HTTP route rules have precedence
当对于给定目标有多个规则时,他们评估出现在VirtualService
的顺序,即,列表中的第一个规则有最高优先级。
为什么优先级很重要?每当某个特定服务的路由纯粹是基于权重的时候,就可以在单个规则中指定它。另一方面,当其他标准(如来自某特定用户的请求)用来路由流量时,指定路由将需要超过一个规则。这就是规则策略必须妥当考虑的地方4,以确保规则按正确顺序评估。
一个广义路由规范的常见模式是提供一个或多个更高优先级规则来满足source/headers的规则,然后提供一个没有匹配标准的单一基于权重的规则,最后提供所有其他情况的流量加权分布。
如,下面的VirtualService
同时包含两个规则,指定对于reviews服务的header中包含名为“Foo”,值为“bar”的所有请求,将要发送到v2实例。剩下的所有请求发送到v1。
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- match:
- headers:
Foo:
exact: bar
route:
- destination:
host: reviews
subset: v2
- route:
- destination:
host: reviews
subset: v1
注意到基于header的规则有更高的优先级。如果它更低的话,这些规则将不会按预期工作,因为基于权重的规则,没有特定匹配标准,所以会首先评估为所有流量单纯路由到v1,即使请求中包含匹配的“Foo” header。一旦一个规则被发现适用于入站请求,它将会立即执行,规则评估进程将会中止。这就是为什么当规则超过一个时,仔细考虑每个规则的优先级是如此重要了。
Destination Rules
一个 DestinationRule 配置了适用于VirtualService
路由发生后的请求策略。它们由服务所有者撰写,描述了熔断,负载均衡设置,TLS设置等。
DestinationRule
同时定义了可寻址的subsets
(即,版本命名),对应目标host。当发送流量到服务的特定版本时,这些子集在VirtualService
路由规则中被使用。
下面的DestinationRule
为reviews服务配置策略和子集:
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: reviews
spec:
host: reviews
trafficPolicy:
loadBalancer:
simple: RANDOM
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
trafficPolicy:
loadBalancer:
simple: ROUND_ROBIN
- name: v3
labels:
version: v3
注意多个策略可以在单一的 DestinationRule
配置中被指定。
Circuit breakers
一个普通的熔断可以基于条件数目设置,如连接和请求限制。
如下 DestinationRule
设置了reviews服务v1版后端服务限制了100个连接。
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: reviews
spec:
host: reviews
subsets:
- name: v1
labels:
version: v1
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
在 circuit-breaking task 中由熔断控制的范例。
DestinationRule evaluation
和路由规则类似,策略和特定host关联,但是如果它们有特定子集,则激活取决于路由规则评估结果。
规则评估进程的第一步评估在VirtualService
中对应被请求host的路由规则(如果有定义),确定当前请求将路由到目标服务的子集(即,特定版本)。接下来,评估与所选子集相对应的一组策略,以确定它们是否适用。
注意:牢记算法的一个细微之处在于,只有在相应的子集被明确路由到特定子集时,才会应用为特定子集的策略。看以下下面的配置,作为reviews服务定义的唯一规则(即,对应VirtualService
没有路由规则)
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: reviews
spec:
host: reviews
subsets:
- name: v1
labels:
version: v1
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
因为这没有为reviews服务定义的特定路由规则,将会适用默认的循环路由行为,大概调用v1实例,如果v1时唯一运行的版本,可能会一直调用它。不过,上面的策略将永远不会被调用,因为默认路由在更低层级完成。规则评估引擎将不知道最终目标,因此无法将子集策略与请求进行匹配。
你可以通过以下两种方式之一修复上述示例。你可以将流量策略上移一个级别,使其适用于任何版本:
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: reviews
spec:
host: reviews
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
subsets:
- name: v1
labels:
version: v1
或者,更好的方式,为服务定义适当路由规则。例如,你可以为“reviews:v1”增加一个简单路由规则。
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
尽管默认istio行为方便的将来自任何源的流量发送到目标服务的所有版本,而没有设置任何规则,但只要需要区别版本,就需要规则。因此,为每个服务设置一个默认规则(从一开始就这样),通常被认为是Istio的最佳实践。
Service Entries
ServiceEntry 用于将附加条目添加到Istio内部维护的服务注册表中。它最常用于在Istio服务网格外启用对服务的请求。如下ServiceEntry 可以用来允许对*.foo.com 域下托管的服务进行外部调用。
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: foo-ext-svc
spec:
hosts:
- *.foo.com
ports:
- number: 80
name: http
protocol: HTTP
- number: 443
name: https
protocol: HTTPS
ServiceEntry
的目标使用hosts
字段指定,它可以是完全限定或通配符的域名。它表示白名单中列出的允许网格中的服务访问的一个或多个服务。
ServiceEntry
不限于外部服务配置,它可以有两种类型:网格内部或网格外部。网格内部条目与其他内部服务一样,但用于向网格显式添加服务。它们可用于添加服务,作为扩展服务网格以包含非托管基础架构的一部分(如,VMs添加一个基于k8s的服务网格)。网格外部条目代表网格外部的服务。对于它们来说,禁用mTLS身份认证,并在客户端执行策略,而不是在通常的服务器端执行内部服务请求。
只要服务条目涉及使用匹配hosts
的服务,就可以与虚拟服务和目标规则一起使用。如下规则用来结合上面的ServiceEntry
规则来为调用 bar.foo.com
外部服务设置10s超时。
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: bar-foo-ext-svc
spec:
hosts:
- bar.foo.com
http:
- route:
- destination:
host: bar.foo.com
timeout: 10s
规则重定向和转发流量,支持为外部目标定义重试,超时和故障注入策略。但,加权(基于版本)路由不能使用,因为没有多个外部服务版本的概念。
在 egress task 了解更多访问外部服务。
Gateways
Gateway 为HTTP/TCP流量配置了负载均衡,通常在网络边缘运行,以便为应用程序启动入口流量。
不同于k8s Ingress,Istio Gateway
只配置L4-L6功能(如,暴露端口,TLS配置)。用户可以使用标准的Istio规则来控制HTTP请求,以及通过绑定VirtualService
来控制进入Gateway
的TCP流量。
如下Gateway
配置一个负载均衡来允许 bookinfo.com
的外部https流量流入网格:
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: bookinfo-gateway
spec:
servers:
- port:
number: 443
name: https
protocol: HTTPS
hosts:
- bookinfo.com
tls:
mode: SIMPLE
serverCertificate: /tmp/tls.crt
privateKey: /tmp/tls.key
为了配置对应的路由,VirtualService
必须定义相同的host,使用gateways
字段绑定Gateway
:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: bookinfo
spec:
hosts:
- bookinfo.com
gateways:
- bookinfo-gateway # <---- bind to gateway
http:
- match:
- uri:
prefix: /reviews
route:
...
在ingress task 中一个完整的ingress gateway 例子。
虽然主要用于管理入口流量,但也可以使用Gateway
对纯粹的内部或出口代理进行建模。无论位置如何,所有网关都可以用相同的方式进行配置和控制。 gateway reference 查看更多细节。