案例描述

(1)了解Istio的基本使用。

(2)了解基于Istio实现流量治理。

(3)了解基于Istio实现服务发布。

规划节点

节点规划,见表1。

表1 节点规划

IP 主机名 节点
10.24.2.5 k8s-master-node1 master节点、仓库节点
10.24.2.6 k8s-worker-node1 node节点

基础准备

已基于软件包chinaskills_cloud_paas_v2.0.iso部署完Kubernetes集群,并将提供的软件包ServiceMesh.tar.gz上传至master节点/root目录下

案例实施

部署Bookinfo应用

Bookinfo简介

Bookinfo应用模仿在线书店的一个分类,显示一本书的信息。页面上会显示一本书的描述,书籍的细节(ISBN、页数等),以及关于这本书的一些评论。

Bookinfo应用分为四个单独的微服务:

● productpage:调用details和reviews两个微服务,用来生成页面;

● details:包含书籍的信息;

● reviews:包含书籍相关的评论,会调用ratings微服务;

● ratings:包含由书籍评价组成的评级信息。

reviews微服务有3个版本:

● v1版本不会调用ratings服务;

● v2版本会调用ratings服务,并使用1到5个黑色星形图标来显示评分信息;

● v3版本会调用ratings服务,并使用1到5个红色星形图标来显示评分信息。

Bookinfo应用的端到端架构如图所示:

98

图1

Bookinfo应用中的几个微服务是由不同的语言编写的。这些服务对Istio并无依赖,但是构成了一个有代表性的服务网格的例子:它由多个服务、多个语言构成,并且reviews服务具有多个版本。

部署应用程序

解压软件包并导入镜像:

1
2
3
[root@k8s-master-node1 ~]# tar -zxf ServiceMesh.tar.gz
[root@k8s-master-node1 ~]# cd ServiceMesh/
[root@k8s-master-node1 ServiceMesh]# docker load -i images/image.tar

部署应用到Kubernetes集群:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@k8s-master-node1 ServiceMesh]# kubectl apply -f bookinfo/bookinfo.yaml
service/details created
serviceaccount/bookinfo-details created
deployment.apps/details-v1 created
service/ratings created
serviceaccount/bookinfo-ratings created
deployment.apps/ratings-v1 created
service/reviews created
serviceaccount/bookinfo-reviews created
deployment.apps/reviews-v1 created
service/productpage created
serviceaccount/bookinfo-productpage created
deployment.apps/productpage-v1 created

查看Pod状态:

1
2
3
4
5
6
[root@k8s-master-node1 ServiceMesh]# kubectl get pods
NAME READY STATUS RESTARTS AGE
details-v1-79f774bdb9-m98sl 1/1 Running 0 46s
productpage-v1-6b746f74dc-snpf9 1/1 Running 0 46s
ratings-v1-b6994bb9-nmws8 1/1 Running 0 46s
reviews-v1-545db77b95-4rtn4 1/1 Running 0 46s

启用对应用程序的外部访问

现在Bookinfo应用程序已成功运行,需要使应用程序可以从外部访问,可以用Istio Gateway来实现这个目标。

使用网关为网格来管理入站和出站流量,可以指定要进入或流出网格的流量。网关配置被用于运行在网格边界的独立Envoy代理,而不是服务工作负载的sidecar代理。

与Kubernetes Ingress API这种控制进入系统流量的其他机制不同,Istio网关充分利用了流量路由的强大能力和灵活性。Istio的网关资源可以配置4-6层的负载均衡属性,如对外暴露的端口、TLS设置等。作为替代应用层流量路由(L7)到相同的API资源,绑定一个常规的Istio虚拟服务到网关,这样就可以像管理网格中其他数据平面的流量一样去管理网关流量。

网关主要用于管理进入的流量,也可以配置出口网关。出口网关为流出网格的流量配置一个专用的出口节点,这可以限制哪些服务可以或应该访问外部网络,或者启用出口流量安全控制为网格添加安全性。

Gateway配置文件如下:

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
[root@k8s-master-node1 ServiceMesh]# cat bookinfo-gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: bookinfo-gateway
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
﹉(“﹉”请学生自行手打,不要复制)
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: bookinfo
spec:
hosts:
- "*"
gateways:
- bookinfo-gateway
http:
- match:
- uri:
exact: /productpage
- uri:
prefix: /static
- uri:
exact: /login
- uri:
exact: /logout
- uri:
prefix: /api/v1/products
route:
- destination:
host: productpage
port:
number: 9080

这个网关指定所有HTTP流量通过80端口流入网格,然后把网关绑定到虚拟服务上。

为应用程序定义Ingress网关:

1
2
3
[root@k8s-master-node1 ServiceMesh]# kubectl apply -f bookinfo-gateway.yaml
gateway.networking.istio.io/bookinfo-gateway created
virtualservice.networking.istio.io/bookinfo created

确认网关创建完成:

1
2
3
[root@k8s-master-node1 ServiceMesh]# kubectl get gateway
NAME AGE
bookinfo-gateway 32s

查看Ingress Gateway:

1
2
3
4
[root@k8s-master-node1 ServiceMesh]# kubectl get svc -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-egressgateway ClusterIP 10.101.130.107 80/TCP,443/TCP 30m
istio-ingressgateway LoadBalancer 10.102.250.102 15021:32634/TCP,80:22092/TCP,443:30119/TCP,31400:30282/TCP,15443:32486/TCP 30m

可以看到Gateway 80端口对应的NodePort端口是22092,在浏览器上通过http://master_IP:22092/productpage访问Bookinfo应用,如图所示:

99

图2

生产测试

使用Curl工具向Bookinfo应用发送请求产生模拟流量。

1
2
3
4
5
6
7
[root@k8s-master-node1 ServiceMesh]# cat curl.sh
#!/bin/bash
while true
do
curl http://10.24.2.5:22092/productpage >/dev/null 2>&1
sleep 1
done

后台运行脚本:

1
2
3
[root@k8s-master-node1 ServiceMesh]# chmod +x curl.sh
[root@k8s-master-node1 ServiceMesh]# bash curl.sh &
[1] 2924

启用Istio

在productpage启用Istio

在productpage微服务中,启用Istio。这个应用的其他部分会继续照原样运行。可以一个微服务一个微服务的逐步启用Istio。启用Istio在微服务中是无侵入的,不用修改微服务代码或者破坏应用,它也能够持续运行并且为用户请求服务。

在使用Istio控制Bookinfo版本路由之前,需要在目标规则中定义好可用的版本。目标规则是Istio流量路由功能的关键部分。可以将虚拟服务视为将流量如何路由到给定目标地址,然后使用目标规则来配置该目标的流量。在评估虚拟服务路由规则之后,目标规则将应用于流量的“真实”目标地址。

编写目标规则配置文件:

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
[root@k8s-master-node1 ServiceMesh]# cat destination-rule-all.yaml
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: productpage
spec:
host: productpage
subsets:
- name: v1
labels:
version: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: reviews
spec:
host: reviews
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
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
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2

创建默认目标规则:

1
2
3
4
5
6
7
[root@k8s-master-node1 ServiceMesh]# kubectl apply -f destination-rule-all.yaml
[root@k8s-master-node1 ServiceMesh]# kubectl get destinationrule
NAME HOST AGE
details details 21s
productpage productpage 21s
ratings ratings 21s
reviews reviews 21s

重新部署productpage微服务,启用Istio:

1
2
3
[root@k8s-master-node1 ServiceMesh]# cat bookinfo/bookinfo.yaml | istioctl kube-inject -f - | kubectl apply -l app=productpage -f -
service/productpage unchanged
deployment.apps/productpage-v1 configured

检查productpage的Pod并且查看每个副本的两个容器。第一个容器是微服务本身的,第二个是连接到它的Sidecar代理:

1
2
3
4
5
6
[root@k8s-master-node1 ServiceMesh]# kubectl get pods
NAME READY STATUS RESTARTS AGE
details-v1-79f774bdb9-np7tt 1/1 Running 0 8m9s
productpage-v1-599f9dc7b8-btdqz 2/2 Running 0 43s
ratings-v1-b6994bb9-nkq7z 1/1 Running 0 8m9s
reviews-v1-545db77b95-xwnwf 1/1 Running 0 8m9s

Kubernetes采取无侵入的和逐步的滚动更新方式用启用Istio的Pod替换了原有的Pod。Kubernetes只有在新的Pod开始运行的时候才会终止老的Pod,它透明地将流量一个一个地切换到新的Pod上。也就是说,它不会在声明一个新的Pod之前结束一个或者以上的Pod。这些操作都是为了防止破坏应用,因此在注入Istio的过程中应用能够持续工作。

在浏览器上登录Grafana(http://master_IP:33000),如图所示:

100

图3

切换到Dashboard管理界面,如图所示:

101

图4

选择Istio Mesh Dashboard,如图所示:

102

图5

切换到Istio Service Dashboard仪表盘,在Service中选择productpage,如图所示:

103

图6

在所有微服务中启用Istio

所有服务启用Istio:

1
[root@k8s-master-node1 ServiceMesh]# cat bookinfo/bookinfo.yaml | istioctl kube-inject -f - | kubectl apply -l app!=productpage -f -

查看应用程序Pod,现在每个Pod的两个容器,一个容器是微服务本身,另一个是连接到它的Sidecar代理:

1
2
3
4
5
6
[root@k8s-master-node1 ServiceMesh]# kubectl get pods
NAME READY STATUS RESTARTS AGE
details-v1-6df75fb475-4stwg 2/2 Running 0 70s
productpage-v1-599f9dc7b8-fprwf 2/2 Running 0 5m2s
ratings-v1-c7b9dfddc-rlmk4 2/2 Running 0 70s
reviews-v2-855b56b89-57k67 2/2 Running 0 64s

再次查看Istio Mesh Dashboard,会发现当前命名空间下所有服务都会出现在服务列表中,如图所示:

104

图7

通过Kiali控住台(http://master_IP:20001)的可视化界面来查看应用程序的拓扑结构,点击Graph按钮,在Namespace下拉菜单中选择命名空间,然后在Display下拉菜单中选中Traffic Animation复选框,就可以看到实时流量动画。如图所示:

105

图8

reviews微服务v1版本不会调用ratings服务,所以图中ratings服务无流量通过。

监控Istio

访问Prometheus控制台(http://master_IP:30090),如图所示:

106

图9

在Expression输入框中输入要查询的参数,然后点击Execute按钮即可在Console中查看查询结果。

查询请求时采用istio_requests_total指标,这是一个标准的Istio指标。

如查询命名空间的所有请求(istio_requests_total{destination_service_namespace=“default”, reporter=“destination”}),如图所示:

107

图10

查询reviews微服务的请求(istio_requests_total{destination_service_namespace=“default”, reporter=“destination”,destination_service_name=“reviews”}),如图所示:

108

图11

灰度发布

部署新版本服务

将v2、v3版本的reviews服务部署到集群中,均为单一版本。新版本的reviews可以正常工作后,实际生产流量将开始到达该服务。在当前的设置下,50%的流量将到达旧版本(1个旧版本的Pod),而另外50%的流量将到达新版本(1个新版本Pod)。

部署v2版本的reviews微服务并开启Istio:

1
2
[root@k8s-master-node1 ServiceMesh]# cat bookinfo/reviews-v2.yaml | istioctl kube-inject -f - | kubectl apply -f -
[root@k8s-master-node1 ServiceMesh]# cat bookinfo/reviews-v3.yaml | istioctl kube-inject -f - | kubectl apply -f -

查看Pod:

1
2
3
4
5
6
7
8
[root@k8s-master-node1 ServiceMesh]# kubectl get pods
NAME READY STATUS RESTARTS AGE
details-v1-6df75fb475-4stwg 2/2 Running 0 5m5s
productpage-v1-599f9dc7b8-fprwf 2/2 Running 0 8m2s
ratings-v1-c7b9dfddc-rlmk4 2/2 Running 0 5m5s
reviews-v2-855b56b89-57k67 2/2 Running 0 5m5s
reviews-v2-855b56b89-49jkx 2/2 Running 0 34s
reviews-v3-7b76df6bbb-f6hhp 2/2 Running 0 29s

访问Bookinfo应用程序页面,如图所示:

109

图12

观察评级上的星标,发现有时返回的页面带有黑色星标(v2版本、大约三分之一的时间),有时带有红色星标(v3版本、大约三分之一的时间),有时不带星标(v1版本、大约三分之一的时间),这是因为没有明确的默认服务版本和路由,Istio将以循环方式将请求路由到所有可用版本,所以三种评分结果出现的概率均为三分之一。

查看实时流量监控,如图所示:

110

图13

可以看到,v2和v3版本的reviews微服务已正常工作,因v2和v3版本会调用ratings服务,所以图中ratings服务也有流量通过。

请求路由

Bookinfo应用程序包含四个独立的微服务,每个微服务都有多个版本。其中一个微服务reviews的3个不同版本已经部署并同时运行。因为没有明确的默认服务版本和路由,Istio将以循环方式将请求路由到所有可用版本。这样将导致在浏览器中访问Bookinfo应用程序时,输出有时包含星级评分,有时则不包含。

Kubernetes方式下控制流量分配需要调整每个Deployment的副本数目。例如,将10%的流量发送到金丝雀版本(v2),v1和v2的副本可以分别设置为9和1。由于在启用Istio不再需要保持副本比例,所以可以安全地设置Kubernetes HPA来管理三个版本Deployment的副本:

1
2
3
[root@k8s-master-node1 ServiceMesh]# kubectl autoscale deployment reviews-v1 --cpu-percent=50 --min=1 --max=10
[root@k8s-master-node1 ServiceMesh]# kubectl autoscale deployment reviews-v2 --cpu-percent=50 --min=1 --max=10
[root@k8s-master-node1 ServiceMesh]# kubectl autoscale deployment reviews-v3 --cpu-percent=50 --min=1 --max=10

如果要仅路由到一个版本,请为微服务设置默认版本的Virtual Service。在这种情况下,Virtual Service将所有流量路由到每个微服务的v1版本。

默认请求路由配置文件如下:

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
[root@k8s-master-node1 ServiceMesh]# cat virtual-service-all-v1.yaml
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

配置默认请求路由:

1
2
3
4
5
[root@k8s-master-node1 ServiceMesh]# kubectl apply -f 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

现在已将Istio配置为路由到Bookinfo微服务的v1版本,最重要的是reviews服务的v1版本。

在浏览器中打开Bookinfo站点,如图所示:

111

图14

此时无论刷新多少次,页面的评分部分都不会显示评级星标。这是因为Istio被配置为将评分服务的所有流量路由到v1版本的reviews,而此版本的服务不调用星级评分服务。

查看实时流量监控,也可以看到此时无流量流向v2和v3版本,如图所示:

112

图15

流量转移

使用下面的命令把50%的流量从reviews:v1转移到reviews:v3(金丝雀版本):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@k8s-master-node1 ServiceMesh]# cat virtual-service-reviews-50-50.yaml 
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
weight: 50
- destination:
host: reviews
subset: v3
weight: 50
[root@k8s-master-node1 ServiceMesh]# kubectl apply -f virtual-service-reviews-50-50.yaml
virtualservice.networking.istio.io/reviews configured

当规则设置生效后,Istio将确保只有50%的请求发送到金丝雀版本,无论每个版本的运行副本数量是多少。

刷新浏览器中的/productpage页面,因为reviews的v3版本可以访问带星级评价服务,而v1版本不能,所以大约有50%的几率会看到页面中带红色星级的评价内容,如图所示:

113

图16

在Kiali上查看实时流量监控,可以看到流量已经流向了v3版本,如图所示:

114

图17

点击productpage服务与reviews服务之间的连线,在右侧可以看到每秒发送到reviews服务的http请求为0.96,如图所示:

115

图18

点击reviews服务和v1版本之间的连线,可以看到v1版本每秒接收到的http请求为0.49,如图所示:

116

图19

点击reviews服务和v3版本之间的连线,可以看到v3版本每秒接收到的http请求为0.47,如图所示:

117

图20

说明流向reviews服务的流量各有50%流向了v1和v3,路由规则应用成功。

假如认为reviews:v3微服务已经稳定,可以通过应用Virtual Service规则将100%的流量路由reviews:v3:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@k8s-master-node1 ServiceMesh]# cat virtual-service-reviews-v3.yaml 
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v3
[root@k8s-master-node1 ServiceMesh]# kubectl apply -f virtual-service-reviews-v3.yaml
virtualservice.networking.istio.io/reviews configured

再次刷新/productpage时,将始终看到带有红色星级评分的书评。

查看实时流量,发现流量全部流向v3,如图所示:

118

图21

流量镜像

流量镜像,也称为影子流量,是一个以尽可能低的风险为生产带来变化的强大的功能。镜像会将实时流量的副本发送到镜像服务。镜像流量发生在主服务的关键请求路径之外。

初始化默认路由规则,将所有流量路由到服务的v1版本:

1
[root@k8s-master-node1 ServiceMesh]# kubectl apply -f virtual-service-all-v1.yaml

改变reviews服务的流量规则,将v1版本的流量镜像到v2版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@k8s-master-node1 ServiceMesh]# cat virtual-service-mirroring.yaml 
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
weight: 100
mirror:
host: reviews
subset: v2
[root@k8s-master-node1 ServiceMesh]# kubectl apply -f virtual-service-mirroring.yaml
virtualservice.networking.istio.io/reviews configured

分布式追踪

分布式追踪可以让用户对跨多个分布式服务网格的1个请求进行追踪分析。这样进而可以通过可视化的方式更加深入地了解请求的延迟,序列化和并行度。

Istio利用Envoy的分布式追踪功能提供了开箱即用的追踪集成。确切地说,Istio提供了安装各种追踪后端服务的选项,并且通过配置代理来自动发送追踪Span到追踪后端服务。

登录Jaeger控制台(http://master_IP:30686),如图所示:

119

图22

从仪表盘左边面板的Service下拉列表中选择productpage并点击Find Traces,如图所示:

120

图23

点击位于最上面的最近一次追踪,查看对应最近一次访问/productpage的详细信息,如图所示:

121

图24

追踪信息由一组Span组成,每个Span对应一个Bookinfo Service。这些Service在执行/productpage请求时被调用,或是Istio内部组件。