解决virtualservice前缀路由匹配冲突问题

警告
本文最后更新于 2021-10-21 00:27,文中内容可能已过时。

背景

当我们有两个virtualservice并且路由匹配都是使用match.uri.prefix,第一个路由r1是匹配/it前缀,第二个路由r2匹配/item前缀。

这时你会发现无论是访问/it、/it/、/it/xxx,/item,/item/,/item/xx都会匹配到r1对应的服务。

由于vs不支持priority,可以通过下面几种方法解决

  1. 合并virtualservice(推荐)
  2. 使用regex匹配路由
  3. 写一个prefix: /it/ 一个exact: /it

下面使用regex的方式来解决这个问题。

一、部署测试服务

部署两个nginx服务用于测试路由

 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
75
76
77
78
79
apiVersion: apps/v1
kind: Deployment
metadata:
  name: n1
  namespace: istio-demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
      version: v1
  template:
    metadata:
      labels:
        app: nginx
        version: v1
    spec:
      containers:
      - name: nginx
        image: nginx:1.14-alpine
        imagePullPolicy: IfNotPresent
        ports:
        - name: http
          containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: n1-svc
  namespace: istio-demo
spec:
  type: ClusterIP
  ports:
  - name: http
    port: 80
    targetPort: 80
  selector:
    app: nginx
    version: v1
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: n2
  namespace: istio-demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
      version: v2
  template:
    metadata:
      labels:
        app: nginx
        version: v2
    spec:
      containers:
      - name: nginx
        image: nginx:1.14-alpine
        imagePullPolicy: IfNotPresent
        ports:
        - name: http
          containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: n2-svc
  namespace: istio-demo
spec:
  type: ClusterIP
  ports:
  - name: http
    port: 80
    targetPort: 80
  selector:
    app: nginx
    version: v2

上面只是单纯的创建了两个nginx应用和两个service,后面通过浏览器访问,观察nginx日志来确认流量进入了哪个应用

二、配置有问题的路由规则

 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
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: r1
  namespace: istio-demo
spec:
  gateways:
  - istio-system/public-gateway
  hosts:
  - 'n1-svc'
  - 'headers.t.cn'
  http:
  - route:
    - destination:
        host: n1-svc
    match:
    - uri:
        prefix: '/it'
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: r2
  namespace: istio-demo
spec:
  gateways:
  - istio-system/public-gateway
  hosts:
  - 'n2-svc'
  - 'headers.t.cn'
  http:
  - route:
    - destination:
        host: n2-svc
    match:
    - uri:
        prefix: /item

测试访问情况:

  1. 首先打开两个控制台观察pod的日志
  2. 在浏览器访问/it、/it/、/it/xxx、/item、/item/、/item/xxx均访问到n1服务上(n2服务的规则失效)
  3. 删除n1的路由匹配规则,此时/item、/item/、/item/xxx均访问到n2服务上

解决方法

修改prefix为regex

 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
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: r1
  namespace: istio-demo
spec:
  gateways:
  - istio-system/public-gateway
  hosts:
  - 'n1-svc'
  - 'headers.t.cn'
  http:
  - route:
    - destination:
        host: n1-svc
    match:
    - uri:
        # 匹配/it/开头或/it的uri
        regex: '(\/it\/.*)|(\/it\/?)'
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: r2
  namespace: istio-demo
spec:
  gateways:
  - istio-system/public-gateway
  hosts:
  - 'n2-svc'
  - 'headers.t.cn'
  http:
  - route:
    - destination:
        host: n2-svc
    match:
    - uri:
        # 匹配/item/开头或/item的uri,这里其实不改也可以,因为r1路由已经不会影响到r2路由了
        regex: '(\/item\/.*)|(\/item\/?)'

经测试 访问/it、/it/、/it/xxx会路由到n1应用 访问/item、/item/、/item/xxx会路由到n2应用

请我喝杯水
SoulChild 微信号 微信号
SoulChild 微信打赏 微信打赏
0%