本节开始学习istio对微服务的流量管理功能,先来看如何配置请求路由,使用istio的流量路由规则可以很容易的控制服务之间的流量和调用。 本节先基于官方文档https://istio.io/latest/zh/docs/tasks/traffic-management/request-routing/完成配置请求路由的实操演练,后续再理解一些概念性的东西。

bookinfo应用简介

前面我们部署的bookinfo应用由4个独立的微服务组成:

istio.jpg

bookinfo应用模仿在线书店的一个分类,显示一本书的信息,页面上会包含书的描述,书的ISBN,页数等详细信息,以及关于本书的评论。 bookinfo应用的4个微服务如下:

  • productpage: 此微服务使用python语言开发,会调用detailsreviews两个微服务,用来生成页面
  • details: 此微服务使用ruby开发,提供数据的详细信息
  • reviews: 此微服务使用java语言开发,提供书的评论信息,它还会调用ratings微服务
  • ratings: 此微服使用NodeJS开发,务提供书的评论组成的评级信息

另外,还需注意reviews微服务部署了3个版本:

  • v1版本不会调用ratings服务
  • v2版本会调用ratings服务,使用1到5个黑色五角星显示评分信息
  • v3版本会调用ratings服务,使用1到5个红色五角星显示评分信息
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
kubectl get deploy -l app=reviews
NAME         READY   UP-TO-DATE   AVAILABLE   AGE
reviews-v1   1/1     1            1           43h
reviews-v2   1/1     1            1           43h
reviews-v3   1/1     1            1           43h

kubectl get pod -l app=reviews
NAME                          READY   STATUS    RESTARTS   AGE
reviews-v1-545db77b95-g7nw7   2/2     Running   0          43h
reviews-v2-7bf8c9648f-wrcqq   2/2     Running   0          43h
reviews-v3-84779c7bbc-xgmlf   2/2     Running   0          43h

reviews服务同一时间在k8s集群中存在3个版本原因有可能是最开始是v1版本,后来想要做一个实验确定V2和V3两个版本哪个版本显示评分信息的方式更好一些,这可能就需要做A/B测试,此时就需要利用istio强大的流量管理功能。

当然,此时部署的bookinfo应用的服务网格还没有配置任何流量管理请求路由的,因此此时请求应用的书籍页面/productpage,显示结果应该随机的, 要看本次请求到哪个版本的reviews服务上,多刷新一次页面,就会发现书籍评论有的时候不包含评分信息、有的时候是黑色星级评分信息、有的时候是红色星级评分信息。

bookinfo-productpage.gif

将请求路由到固定版本的微服务上

首先要做的实验是尝试用istio控制将bookinfo所有流量路由到v1版本的reviews服务。在使用istio控制bookinfo版本路由之前,需要先创建默认的DestinationRule。 以profile=defaultprofile=demo部署的istio默认开启了自动双向TLS,因此创建默认的DestinationRule需应用下面的文件:

1
2
3
4
5
kubectl apply -f samples/bookinfo/networking/destination-rule-all-mtls.yaml
destinationrule.networking.istio.io/productpage created
destinationrule.networking.istio.io/reviews created
destinationrule.networking.istio.io/ratings created
destinationrule.networking.istio.io/details created

上面的命令分别为4个微服务创建了destinationrule,看一下destination-rule-all-mtls.yaml的内容:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: productpage
spec:
  host: productpage
  trafficPolicy:
    tls:
      mode: ISTIO_MUTUAL
  subsets:
  - name: v1
    labels:
      version: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: reviews
spec:
  host: reviews
  trafficPolicy:
    tls:
      mode: ISTIO_MUTUAL
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
  - name: v3
    labels:
      version: v3
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: ratings
spec:
  host: ratings
  trafficPolicy:
    tls:
      mode: ISTIO_MUTUAL
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
  - name: v2-mysql
    labels:
      version: v2-mysql
  - name: v2-mysql-vm
    labels:
      version: v2-mysql-vm
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: details
spec:
  host: details
  trafficPolicy:
    tls:
      mode: ISTIO_MUTUAL
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
---

上面reviews微服务的destinationrule的subsets包含v1, v2, v3。

接下来使用下面的命令创建VirtualService:

1
2
3
4
5
6
cd istio-1.10.2 #进入istio安装包的解压目录
kubectl apply -f samples/bookinfo/networking/virtual-service-all-v1.yaml
virtualservice.networking.istio.io/productpage created
virtualservice.networking.istio.io/reviews created
virtualservice.networking.istio.io/ratings created
virtualservice.networking.istio.io/details created

上面命令分别为4个微服务创建了各自的virtualservice,看一下virtual-service-all-v1.yaml的内容:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: productpage
spec:
  hosts:
  - productpage
  http:
  - route:
    - destination:
        host: productpage
        subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - route:
    - destination:
        host: ratings
        subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: details
spec:
  hosts:
  - details
  http:
  - route:
    - destination:
        host: details
        subset: v1
---

reviews微服务的VirtualService配置了路由的目标只到v1 subset,其他服务在请求reviews时将只被路由到reviews v1。 istio配置的传播是最终一致性的,等待几秒钟后,多次刷新/prodctpage页,确认书籍评不再不包含评分信息,说明请求一直被路由到v1版本的reviews服务。

基于用户身份进行请求路由

接下来将尝试通过修改路由配置,将指定用户的请求路由到指定版本的服务上。这里将来自用户名为jason的请求路由到v2版本的reivews服务上。 需要注意,istio对用户身份没有内置任何的机制,istio并不会与我们微服务中的业务逻辑耦合,因实验室此istio代理并不知道具体是哪个一个用户在访问服务。 这里实际上是将productpage服务到reviews服务的请求上加上了一个end-user的请求头,通过判断请求头实现的。

执行下面的命令:

1
2
kubectl apply -f samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml
virtualservice.networking.istio.io/reviews configured

上面的命令对reviews服务的virtualservice做了修改,virtual-service-reviews-test-v2.yaml的内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
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

请求头中end-user=jason的路由目标是reviews-v2,其他是reviews-v1。测试以jason登录(密码任意输入),登录后多次刷新/productpage页面,书籍的评论都一直包含黑星评级,而以其他用户名登录或匿名不登录访问时书籍评论都不包含星级评论。 这说明已经成功配置按用户身份的路由控制。

总结

经过本节的两个练习,使用istio将100%的请求流量都路由到了v1版本的reviews服务,设置一条路由规则,根据productpage服务发起的请求中的end-user请求头,选择性地将特定的流量路由到v2版本的reviews服, 已经体验了istio在对配置请求路由方面的管理微服务间流量的能力。实际上为了实现这些能力,Istio对部署在Kubernetes上的Pod和Service有一些基本的要求,具体整理如下:

  • Service的端口必须正确命名:命名的规范是<protocol>[-<suffix>],其中suffix后缀部分可以省略。如在bookinfo示例中的reviews Service:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    apiVersion: v1
    kind: Service
    metadata:
      name: reviews
      labels:
        app: reviews
    spec:
      ports:
      - port: 9080
        name: http
      selector:
        app: reviews
    

    name为http,表示这是一个http服务,这样才可以使用istio的7层路由功能,才可以使用http header。port命名支持的protocol包含:httphttp2grpcmongoredis,istio可以通过这些协议的内容来实现不同的路由功能。如果对Kubernetes Service Port的命名没有指定protocol的前缀,则Istio将认为该端口是普通的TCP流量。

  • Service的关联:Pod必须被关联到Kubernetes服务上。如果一个Pod关联到多个Service上,则这些Service不能在同一端口上使用不同的协议,例如HTTP和TCP

  • Deployment应该带有app和version的Label:在使用Kubernetes的Deployment部署Pod的时候,应该显示的为Deployment加上app及version标签。app标签会在分布式追踪的过程中被用来加入上下文信息,istio还会用app和versio标签来给遥测metrics加入上下文数据

  • 应用UID: 确保你的Pod不会以用户ID(uid)为1337的用户运行应用(因为在envoy代理sidecar中的运行用户uid是1337)

参考