背景
使用Istio在做微服务分流的时候,可以根据Header或是PATH来匹配七层流量,并分流。
目标
使用bookinfo示例,对reviews做灰度发布,通过匹配Http Header实现分流;
过程
-
在k8s集群节点上,通过Curl命令,指定Header,直接访问reviews服务时,没有实现分流;
-
通过进入productpage pod的网络空间,指定Header能实现分流;
-
在相同的Namespace下,创建一个pod,在该Pod中,指定Header访问服务,未实现分流。
-
给这个Pod 注入Sidecar,能实现分流。
-
在不同的Namespace下,注入Sidecar的Pod中访问,能实现分流。
问题
-
为什么直接访问,指定Header无法实现分流?
-
为什么使用未注入Sidecar的容器访问,无法实现分流?
原因:
上述两种情况,是servicemesh外的流量,需要经过ingress或是gateway来访问。
解决方法
使用Nginx Ingress网关来,给网关注入Sidecar。
在使用自定义Header来实现分流功能时,需要Match Request Host,因此在使用使用Nginx Ingress做网关时,需要Rewrite Host Header,指定Upstream的Host。
给Ingress设置Annotation nginx.ingress.kubernetes.io/service-upstream: reviews.test.svc.cluster.local
。
环境
通过KubeSphere界面创建灰度发布,通过Match Header来实现分流。
本质上是操作VirtualService
k get virtualservices.networking.istio.io reviews -oyaml
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
creationTimestamp: "2021-02-02T02:59:17Z"
generation: 29
labels:
app: reviews
app.kubernetes.io/name: bookinfo
app.kubernetes.io/version: v1
name: reviews
namespace: dsds
spec:
hosts:
- reviews
http:
- match:
- headers:
end-user:
exact: zack
route:
- destination:
host: reviews
port:
number: 9080
subset: v2
weight: 100
- route:
- destination:
host: reviews
port:
number: 9080
subset: v1
weight: 100
FAQ
- 如何使用curl时,指定Header
for i in {1..10000}; do curl -H 'end-user: zack' -H 'Host: reviews.dsds.svc.cluster.local' -I 10.233.45.153:9080;sleep 0.1;done
- 在做灰度发布的时候,是不是一定要让流量先经过Service?能不能直接把流量打到Pod上面?因为每个Pod有了Sidecar后,相当于是经过了一层envoy proxy,那么是不是可以自动路由到其他的Pod?
不行。必须先经过Service,VirtualService、DestinationRule的规则才能生效。
- 为什么非要经过网关解决?
其实istio 有 servicemesh cluster概念,注入了sidecar的容器都称之为在servicemesh cluster内,网络访问符合virtualService/DestinationRule定义的规则。因此,把网关注入Sidecar后,然后流量从网关进入转发到对应的服务上,就能解决。
上面的解释有点解释不通,比如经过Ingress Gateway作网关的时候,istio-ingressgateway就未注入Sidecar。
另外经过测试,如果不经过网关,直接访问服务,会发现virtulservice的设置并没有生效。
设置流量比例,本质是通过vitualservice的实现流量分发,此时并不依赖HTTP。说明跟http header没有太大关系,之前不经过网关直接访问服务实现Http 匹配Header不生效,一直以为是Virtualservice的Host不匹配Request的Header头部的原因,其实方向错了。因为直接访问服务的时候整个Virtualservcie压根就没有生效。
问题:为什么不经过网关直接访问服务时,Virtualservice就是不生效,而是使用了Service Ipvs那一套呢
猜想:如果从网关或是从注入过sidecar的pod内来访问时,会经过virtualservice规则的过滤;如果是直接访问服务时,会优先使用service ipvs的转发规则。 换言之:这里有两套转发规则:envoy及ipvs,它们生效的先后顺序决定最终结果。这里需要继续深入调研。
这个问题参考下面这个问题解决。
virtualservice destinationrule里面定义的规则,是不是就是修改注入sidecar中envoy的过滤规则呢?
其实并不完全对,想象一下这个场景。如果上面的问题成立,那么在做版本流量分流时,此时两版本的pod都会有sidecar,如果规则生效,意味着一个pod需要把流量发到另一个Pod才可行。
可实际上并不是这样的。可以这样理解,virtualservice的规则是路由规则,是在这两个版本pod的前面的一个sidecar envoy中生效的。这样,它就知道如何把流量准确路由到不同的版本中。而Destinationrule可以理解成设置这个pod中的sidecar envoy的规则。
通过这个模型,就理解了上一个问题了,因为经过Ingress Gateway时,这个网关注入了sidecar后,可以配置上游的Virtualservice规则。
另外 istio-ingressgateway 本身就是个envoy,类似于一个单独的sidecar,因此原理一样。
是不是必须负载注入sidecar,才可以使用virtualservice?
不一定,有这个场景也是生效的:client —> istio-ingressgateway —-> serviceA (未注入sidecar)。此时的virtualservice规则也是生效的,因为它是配置在istio-ingressgateway上的(即负载的前面的一个转发节点)。