流量路由管理是Istio最重要的功能。我们可以通过路由规则轻松地把请求流量导入不同的服务版本中,可以很容易地实现A/B测试、灰度发布这类需要复杂技术才能实现的功能。Istio的流量路由管理如图7-1所示。
Envoy代理会根据路由规则把请求转发到相应服务实例的Pod上,默认情况下Enovy代理会把流量以轮询的方式转到后端服务实例的Pod上。通过设置路由规则,我们可以把对服务的请求流量按百分比转发到不同的版本上。如图7-1的上半部分所示,把Service A请求Service B的流量进行拆分,95%的流量路由到生产环境正在使用的版本,5%的流量路由到新的实验版本。
Envoy代理还可以提取请求的信息,根据请求的相关信息来拆分流量,如图7-1的下半部分所示,我们可以根据服务的请求头User-agent把来自Android和iPhone用户请求转发到不同的服务版本,把iPhone用户流量导入到实验版本中的。
图7-1 Istio流量路由管理(图片来源:Istio官方网站)
Istio的流量路由管理流程如图7-2所示。
通过规则配置API,用户可配置路由规则,Pilot将用户配置的路由规则转换为Envoy代理需要的配置格式,并分发给Envoy代理。此处用户配置的规则是:对于http://serviceb.example.com 的访问,99%的流量转发到v1.5版本,1%的流量转发到v2.0-alpha版本。这是为了把线上流量引入测试待上线的版本。
用户通过Pilot提供的路由规则管理API来创建、更新、删除路由规则,当路由规则发生改变时,Pilot会把路由规则下发到每一个Envoy代理上,由于Envoy会拦截服务间的所有流量,Envoy代理根据这些路由规则来决定服务的请求应该发送到哪一个后端服务实例Pod上,而这些对服务调用方来说是完全透明的,服务调用方不需要做出任何改变。
请求进入服务网格后的数据流向如图7-3所示。
Ingress gateway是外部访问网格内服务的流量入口,所有外部请求流量都会经过这里。Ingress gateway类似于Kubernetes的Ingress Controller的实现,但是Ingress gateway并不直接使用Kubernetes的Ingress规则,在Istio中需要单独配置Ingress gateway。正由于有独立于Kubernetes的Ingress,所以它比Kubernetes的Ingress提供了更多的功能特性,比如,它可以使用服务路由管理功能。Egress gateway是一个可选的组件,它可以作为网格内服务访问外部服务的流量出口,使用它可以方便地管理网格内服务调用外部服务的行为,也可以方便地使用服务路由管理等功能。
图7-2 Istio的流量路由管理流程(图片来源:Istio官方网站)
图7-3 服务网格中的数据流向(图片来源:Istio官方网站)
外部请求通过Ingress gateway进入网格内部,然后被路由到网格内部的具体服务上,服务之间相互调用配合来完成用户的请求,最后由Ingress gateway把请求的响应数据返回给外部调用方。当网格中的服务需要访问外部服务时,可以直接通过跟随服务一起部署的Envoy代理来访问外部服务,也可以通过统一部署的Egress gateway来访问外部服务。
【实验前的准备】
进行本章实验前,需要先执行如下的前置步骤。
1)下载实验时用到的源码仓库:
$ sudo yum install -y git $ git clone https://github.com/mgxian/istio-lab Cloning into 'istio-lab'... remote: Enumerating objects: 247, done. remote: Counting objects: 100% (247/247), done. remote: Compressing objects: 100% (173/173), done. remote: Total 774 (delta 153), reused 164 (delta 73), pack-reused 527 Receiving objects: 100% (774/774), 283.00 KiB | 229.00 KiB/s, done. Resolving deltas: 100% (447/447), done. $ cd istio-lab
2)开启default命名空间的自动注入功能:
$ kubectl label namespace default istio-injection=enabled namespace/default labeled
3)部署用于测试的服务:
$ kubectl apply -f service/go/service-go.yaml $ kubectl apply -f service/node/service-node.yaml $ kubectl apply -f service/lua/service-lua.yaml $ kubectl apply -f service/python/service-python.yaml $ kubectl apply -f service/js/service-js.yaml $ kubectl get pod NAME READY STATUS RESTARTS AGE service-go-v1-7cc5c6f574-tndgb 2/2 Running 0 3m11s service-go-v2-7656dcc478-xtqwz 2/2 Running 0 3m11s service-js-v1-55756d577-jn4w9 2/2 Running 0 3m4s service-js-v2-86bdfc86d9-5gbxm 2/2 Running 0 3m4s service-lua-v1-5c9bcb7778-tj87t 2/2 Running 0 3m8s service-lua-v2-75cb5cdf8-nldtq 2/2 Running 0 3m8s service-node-v1-d44b9bf7b-fh257 2/2 Running 0 3m10s service-node-v2-86545d9796-scztl 2/2 Running 0 3m10s service-python-v1-79fc5849fd-f8bxp 2/2 Running 0 3m6s service-python-v2-7b6864b96b-5drn4 2/2 Running 0 3m6s