istio 1.10学习笔记08: Istio流量管理之TCP流量转移
2021-07-25
上一节我们学习了使用Istio Gateway将集群内的http服务暴露到集群外部。 Istio Gateway在接入集群外部流量时与K8S的Ingress类似istio-ingressgateway组件相当于k8s里的ingress-controller。 Istio Gateway对于K8S的不同之处在于在Istio Gateway资源中只定义对外暴露的端口、协议、域名,对于路由信息需要使用Istio的虚拟服务VirtualService的路由规则来配置,这样就可以将Istio提供的各种各样的功能应用到接入集群的流量上。
本节将首先学习如何使用Istio Gateway将集群内的tcp服务暴露到集群外部,同时体验Istio流量管理的TCP流量转移功能,体验如何使用Istio将TCP流量从微服务的一个版本逐步迁移到另一个版本。
准备测试环境,部署两个版本的tcp-echo服务 #
创建名称为istio-io-tcp-traffic-shifting
的命名空间,并将其标记为自动注入Istio Sidecar。
1kubectl create namespace istio-io-tcp-traffic-shifting
2kubectl label namespace istio-io-tcp-traffic-shifting istio-injection=enabled
部署v1和v2两个版本的tcp-echo微服务:
1kubectl apply -f samples/tcp-echo/tcp-echo-services.yaml -n istio-io-tcp-traffic-shifting
上面命令向k8s部署了以下内容:
1kubectl get svc,deploy,pod -n istio-io-tcp-traffic-shifting
2NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
3service/tcp-echo ClusterIP 10.109.148.168 <none> 9000/TCP,9001/TCP 7m40s
4
5NAME READY UP-TO-DATE AVAILABLE AGE
6deployment.apps/tcp-echo-v1 1/1 1 1 7m40s
7deployment.apps/tcp-echo-v2 1/1 1 1 7m40s
8
9NAME READY STATUS RESTARTS AGE
10pod/tcp-echo-v1-7dd5c5dcfb-l886c 2/2 Running 0 7m40s
11pod/tcp-echo-v2-56cd9b5c4f-slsb7 2/2 Running 0 7m40s
tcp-echo-services.yaml的内容如下:
1apiVersion: v1
2kind: Service
3metadata:
4 name: tcp-echo
5 labels:
6 app: tcp-echo
7 service: tcp-echo
8spec:
9 ports:
10 - name: tcp
11 port: 9000
12 - name: tcp-other
13 port: 9001
14 # Port 9002 is omitted intentionally for testing the pass through filter chain.
15 selector:
16 app: tcp-echo
17---
18apiVersion: apps/v1
19kind: Deployment
20metadata:
21 name: tcp-echo-v1
22 labels:
23 app: tcp-echo
24 version: v1
25spec:
26 replicas: 1
27 selector:
28 matchLabels:
29 app: tcp-echo
30 version: v1
31 template:
32 metadata:
33 labels:
34 app: tcp-echo
35 version: v1
36 spec:
37 containers:
38 - name: tcp-echo
39 image: docker.io/istio/tcp-echo-server:1.2
40 imagePullPolicy: IfNotPresent
41 args: [ "9000,9001,9002", "one" ]
42 ports:
43 - containerPort: 9000
44 - containerPort: 9001
45---
46apiVersion: apps/v1
47kind: Deployment
48metadata:
49 name: tcp-echo-v2
50 labels:
51 app: tcp-echo
52 version: v2
53spec:
54 replicas: 1
55 selector:
56 matchLabels:
57 app: tcp-echo
58 version: v2
59 template:
60 metadata:
61 labels:
62 app: tcp-echo
63 version: v2
64 spec:
65 containers:
66 - name: tcp-echo
67 image: docker.io/istio/tcp-echo-server:1.2
68 imagePullPolicy: IfNotPresent
69 args: [ "9000,9001,9002", "two" ]
70 ports:
71 - containerPort: 9000
72 - containerPort: 9001
使用Istio Gateway将tcp服务tcp-echo暴露到集群外部 #
查看一下istio-ingressgateway组件的service:
1kubectl get svc istio-ingressgateway -n istio-system -o yaml
1apiVersion: v1
2kind: Service
3metadata:
4 labels:
5 app: istio-ingressgateway
6 name: istio-ingressgateway
7 namespace: istio-system
8spec:
9 clusterIP: 10.106.130.216
10 clusterIPs:
11 - 10.106.130.216
12 externalIPs:
13 - 192.168.96.50
14 externalTrafficPolicy: Cluster
15 ipFamilies:
16 - IPv4
17 ipFamilyPolicy: SingleStack
18 ports:
19 - name: status-port
20 nodePort: 31723
21 port: 15021
22 protocol: TCP
23 targetPort: 15021
24 - name: http2
25 nodePort: 30709
26 port: 80
27 protocol: TCP
28 targetPort: 8080
29 - name: https
30 nodePort: 31482
31 port: 443
32 protocol: TCP
33 targetPort: 8443
34 - name: tcp
35 nodePort: 32432
36 port: 31400
37 protocol: TCP
38 targetPort: 31400
39 - name: tls
40 nodePort: 31499
41 port: 15443
42 protocol: TCP
43 targetPort: 15443
44 selector:
45 app: istio-ingressgateway
46 istio: ingressgateway
47 sessionAffinity: None
48 type: LoadBalancer
49status:
50 loadBalancer: {}
注意istio-ingressgateway的Service的ports中name为tcp的端口31400,这个端口就是用来接入tcp流量到集群内部的。 暴露tcp服务与http服务不同,多个http服务可以使用80和443结合具体hostname域名的路由统一搞定; 而暴露每个tcp服务都需要一个单独的端口, 默认部署的istio-ingressgateway Service中已经为我们设置好了一个31400,可以直接使用,但如果还想暴露另外一个tcp服务到集群外部的话,就需要修改istio-ingressgateway Service,添加新的tcp端口。
注意因为istio-ingressgateway Service具有externalIP, 这里是192.168.96.50,我们可以直接使用192.168.96.50:31400访问暴露的服务,如果没有externalIP的话,就要使用31400对应的NodePort 32343来问。
搞清楚istio-ingressgateway的作用后,再看一下如何创建istio Gateway,samples/tcp-echo/tcp-echo-all-v1.yaml的内容如下:
1apiVersion: networking.istio.io/v1alpha3
2kind: Gateway
3metadata:
4 name: tcp-echo-gateway
5spec:
6 selector:
7 istio: ingressgateway
8 servers:
9 - port:
10 number: 31400
11 name: tcp
12 protocol: TCP
13 hosts:
14 - "*"
15---
16apiVersion: networking.istio.io/v1alpha3
17kind: DestinationRule
18metadata:
19 name: tcp-echo-destination
20spec:
21 host: tcp-echo
22 subsets:
23 - name: v1
24 labels:
25 version: v1
26 - name: v2
27 labels:
28 version: v2
29---
30apiVersion: networking.istio.io/v1alpha3
31kind: VirtualService
32metadata:
33 name: tcp-echo
34spec:
35 hosts:
36 - "*"
37 gateways:
38 - tcp-echo-gateway
39 tcp:
40 - match:
41 - port: 31400
42 route:
43 - destination:
44 host: tcp-echo
45 port:
46 number: 9000
47 subset: v1
应用上面的tcp-echo-all-v1.yaml到k8s中:
1kubectl apply -f samples/tcp-echo/tcp-echo-all-v1.yaml -n istio-io-tcp-traffic-shifting
上面的命令执行后,创建了目标规则tcp-echo-destination
,此目标规则应用到了目标服务k8s serivcetcp-echo
上,并配置了服务子集(subset),v1和v2两个服务子集分别对应labelversion=v1
和labelversion=v2
的服务实例。
上面的命令执行后还创建了Gateway tcp-echo-gateway
,这个gateway匹配了任意主机名的31400端口,但光有Gateway不行,还需要使用虚拟服务配置路由规则,这里的路由规则是将tcp-echo-gateway
gateway 31400端口的流量路由到目标k8s服务tcp-echo服务子集的9000端口上。
在集群外部使用nc
命令测试:
1for i in {1..10}; do \
2sh -c "(date; sleep 1) | nc 192.168.96.50 31400"; \
3done
4one Sun Jul 25 15:00:41 CST 2021
5one Sun Jul 25 15:00:42 CST 2021
6one Sun Jul 25 15:00:43 CST 2021
7one Sun Jul 25 15:00:44 CST 2021
8one Sun Jul 25 15:00:45 CST 2021
9one Sun Jul 25 15:00:46 CST 2021
10one Sun Jul 25 15:00:47 CST 2021
11one Sun Jul 25 15:00:48 CST 2021
12one Sun Jul 25 15:00:49 CST 2021
13one Sun Jul 25 15:00:50 CST 2021
10个请求中的输出结果都是one
说明请求流量被100%的路由到了v1版本的服务。
接下来通过以下命令,将20%流量从tcp-echo:v1
迁移到tcp-echo:v2
:
1kubectl apply -f samples/tcp-echo/tcp-echo-20-v2.yaml -n istio-io-tcp-traffic-shifting
tcp-echo-20-v2.yaml文件的内容如下,
1apiVersion: networking.istio.io/v1alpha3
2kind: VirtualService
3metadata:
4 name: tcp-echo
5spec:
6 hosts:
7 - "*"
8 gateways:
9 - tcp-echo-gateway
10 tcp:
11 - match:
12 - port: 31400
13 route:
14 - destination:
15 host: tcp-echo
16 port:
17 number: 9000
18 subset: v1
19 weight: 80
20 - destination:
21 host: tcp-echo
22 port:
23 number: 9000
24 subset: v2
25 weight: 20
通过虚拟服务tcp-echo路由规则中的权重weight分配,将80%流量留给tcp-echo:v1
,将20%流量留给tcp-echo:v2
。
此时在集群外部再次使用nc命令测试:
1for i in {1..10}; do \
2sh -c "(date; sleep 1) | nc 192.168.96.50 31400"; \
3done
4two Sun Jul 25 15:04:41 CST 2021
5one Sun Jul 25 15:04:42 CST 2021
6one Sun Jul 25 15:04:43 CST 2021
7one Sun Jul 25 15:04:44 CST 2021
8one Sun Jul 25 15:04:45 CST 2021
9one Sun Jul 25 15:04:46 CST 2021
10two Sun Jul 25 15:04:47 CST 2021
11one Sun Jul 25 15:04:48 CST 2021
12one Sun Jul 25 15:04:49 CST 2021
13one Sun Jul 25 15:04:50 CST 2021
10个请求中差不多有20%的请求被路由到了版本v2的服务商。
以上利用了istio的路由权重特性完成了将tcp-echo服务的一部分TCP流量从旧版本迁移到了新版本。