本文的目的:指定请求header中特定kv的路由到V2版本。
首先明确两个istio中的概念。
- VirtualService:配置路由规则,控制请求流量如何分发到服务上。
- DestinationRule:路由生效后,配置请求和应用的策略集。
为了更好的呈现操作过程和步骤,实验中的yaml文件放在最后一节中
部署服务
kubectl create ns canary
kubectl label ns canary istio-injection=enabled
kubectl apply -f canary.yaml -n canary
kubectl apply -f toolbox.yaml -n canary
- 查看pod信息
xxx@xxx-virtual-machine:~/istio/101-master/module12/istio/5.canary$ kubectl get pod -n canary
NAME READY STATUS RESTARTS AGE
canary-5d48fc54d5-7wc5d 2/2 Running 0 9m37s
toolbox-78555898fb-ntsc4 2/2 Running 0 9m36s
进到客户端toolbox容器中
部署新版本服务
两个版本的label一个是v1,一个v2.
kubectl apply -f canary-v2.yaml -n canary
查看版本部署情况
xxx@xxx-virtual-machine:~$ kubectl get pod -n canary --show-labels -l app=canary -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
canary-5d48fc54d5-7wc5d 2/2 Running 0 5h48m 172.17.0.11 minikube <none> <none> app=canary,pod-template-hash=5d48fc54d5,security.istio.io/tlsMode=istio,service.istio.io/canonical-name=canary,service.istio.io/canonical-revision=v1,version=v1
canary-v2-599c5bc865-lvdl4 2/2 Running 0 3m31s 172.17.0.13 minikube <none> <none> app=canary,pod-template-hash=599c5bc865,security.istio.io/tlsMode=istio,service.istio.io/canonical-name=canary,service.istio.io/canonical-revision=v2,version=v2
查看service信息
xxx@xxx-virtual-machine:~$ kubectl get svc -n canary -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
canary ClusterIP 10.99.158.15 <none> 80/TCP 5h47m app=canary
xxx@xxx-virtual-machine:~$ kubectl get ep -n canary -o wide
NAME ENDPOINTS AGE
canary 172.17.0.11:80,172.17.0.13:80 5h47m
配置istio规则
service也可以进行灰度发布的流量控制,但是属于粗粒度的,比如上述service中有两个pod,则流量就会有50%的到新版本中。这样就不够灵活。 为了解决上述痛点,
- istio引入了DestinationRule(简称DR)对service代理的不同label的pod进行分组管理定义(即为subsets,同时还可以定义负载均衡策略);
- 然后引入了VirtualService(简称VS)对DestinationRule中定义的分组进行流量管理。定义哪些特征的流量路由到DR中定义的哪个subset中,流入的流量比例是多少。
DR和VS中都有一个必填字段:hosts,代表对应的service信息。
k apply -f istio-specs.yaml -n canary
该demo中配置了请求header中有user是jesse的就会路由到DR中定义的v2 subset中。 当然也可以使用weight进行精确比例路由进行分组,此处不再演示。
还可以使用上一篇# 【玩转服务网格】初试Istio中提到的istioctl检查路由规则是否已经下发到客户端toolbox的sidecar中。
istioctl pc route -n canary toolbox-78555898fb-ntsc4 -ojson
找到domains为canary的route内容,可以看到确实已经完成下发。
进一步查看下cluster是canary的endpoint信息。
xxx@xxx-virtual-machine:~/istio/101-master/module12/istio/6.fault-inject$ istioctl pc ep -n canary toolbox-78555898fb-ntsc4 | grep canary
172.17.0.11:80 HEALTHY OK outbound|80|v1|canary.canary.svc.cluster.local
172.17.0.11:80 HEALTHY OK outbound|80||canary.canary.svc.cluster.local
172.17.0.13:80 HEALTHY OK outbound|80|v2|canary.canary.svc.cluster.local
172.17.0.13:80 HEALTHY OK outbound|80||canary.canary.svc.cluster.local
进入客户端toolbox中,进行模拟请求
curl canary/hello -H "user: jesse"
其他的路由匹配方式
-
uri、scheme、method、authority:4个字段都是StringMatch类型,在匹配请求时都支持exact、prefix和regex三种模式的匹配,分别表示完全匹配输入的字符串,前缀方式匹配和正则表达式匹配。
-
headers:匹配请求中的Header,是一个Map类型。Map的Key是字符串类型,Value 仍然是 StringMatch 类型。即对于每一个 Header 的值,都可以使用精确、前缀和正则三种方式进行匹配。如下所示为自定义headers中source的取值为“north”,并且uri以“/advertisement”开头的请求:
- match:
- headers:
source:
exact: north
uri:
prefix: "/advertisement/"
-
port:表示请求的服务端口。大部分服务只开放了一个端口,这也是在微服务实践中推荐的做法,在这种场景下可以不用指定port。
-
sourceLabels:是一个 map 类型的键值对,表示请求来源的负载匹配标签。这在很多时候非常有用,可以对一组服务都打一个相同的标签,然后使用sourceLabels字段对这些服务实施相同的流量规则。在Kubernetes平台上,这里的Label就是Pod上的标签。
http:
- match:
- sourceLables:
app: frontend
version: v2
- gateways:表示规则应用的Gateway名称,语义同VirtualService上面的gateways定义,是一个更细的Match条件,会覆盖在VirtualService上配置的gateways。
文章中用到的yaml
- toolbox.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: toolbox
spec:
replicas: 1
selector:
matchLabels:
app: toolbox
template:
metadata:
labels:
app: toolbox
access: "true"
spec:
containers:
- name: toolbox
image: centos
command:
- tail
- -f
- /dev/null
- canary.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: canary
spec:
replicas: 1
selector:
matchLabels:
app: canary
template:
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "80"
labels:
app: canary
version: v1
spec:
containers:
- name: canary
imagePullPolicy: Always
image: cncamp/httpserver:v1.0-metrics
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: canary
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
selector:
app: canary
- canary-v2.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: canary-v2
spec:
replicas: 1
selector:
matchLabels:
app: canary
template:
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "80"
labels:
app: canary
version: v2
spec:
containers:
- name: canary
imagePullPolicy: Always
image: cncamp/httpserver:v2.0-metrics
ports:
- containerPort: 80
- istio-specs.yaml
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: canary
spec:
hosts:
- canary
http:
- match:
- headers:
user:
exact: jesse
route:
- destination:
host: canary
subset: v2
- route:
- destination:
host: canary
subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: canary
spec:
host: canary
trafficPolicy:
loadBalancer:
simple: RANDOM
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
trafficPolicy:
loadBalancer:
simple: ROUND_ROBIN