Want to specify rules in VirtualService file where two or more services have same rules

1/20/2020

I have deployed eight services on Kubernetes with Istio sidecar injection. I want to set-up routing rules in VirtualService where three services have same rule. Rules:-

  - match:
    - headers:
        location:
          exact: pune
      uri:
        prefix: /wagholi
    route:
    - destination:
        host: wagholi
        port:
          number: 8080
      uri:
        prefix: /yerwada
    route:
    - destination:
        host: yerwada
        port:
          number: 8080
      uri:
        prefix: /hadapsar
    route:
    - destination:
        host: hadapsar
        port:
          number: 8080
  - match:
    - headers:
        location: 
          exact: mumbai
      uri:
        prefix: /chatraparishivajiterminal
    route:
    - destination:
        host: chatraparishivajiterminal
        port:
          number: 8080
      uri:
        prefix: /kalyan
    route:
    - destination:
        host: kalyan
        port:
          number: 8080
  - match:
    - headers:
        location: 
          exact: Pimpari
      uri:
        prefix: /akurdi
    route:
    - destination:
        host: akurdi
        port:
          number: 8080
      uri:
        prefix: /ravet
    route:
    - destination:
        host: ravet
        port:
          number: 8080

In this scenario, If I set location pune in headers and then try to call service with name wagholi it should call wagholi and if I hit hadapsar then hadapsar. If I set the location as Pimpri and call ravet then it should call ravet only. Is there any scenario to do so !!!!!

-- Balkrishna
gateway
istio
kubernetes
kubernetes-ingress
routing

1 Answer

1/21/2020

I have made a reproduction of your question with 3 simple nginx pods, the problem is I couldn't make it work with just 1 header and 3 uri.

So i made it another way, every match of virtual service has it's own header and uri.

Check below example.

We have 3 pods -> 3 services -> virtual service -> gateway -> ingressgateway

Deployment 1

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx1
spec:
  selector:
    matchLabels:
      run: nginx1
  replicas: 1
  template:
    metadata:
      labels:
        run: nginx1
        app: frontend
    spec:
      containers:
      - name: nginx1
        image: nginx
        ports:
        - containerPort: 80
        lifecycle:
          postStart:
            exec:
              command: ["/bin/sh", "-c", "echo Hello nginx1 > /usr/share/nginx/html/index.html"]

Deployment 2

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx2
spec:
  selector:
    matchLabels:
      run: nginx2
  replicas: 1
  template:
    metadata:
      labels:
        run: nginx2
        app: frontend2
    spec:
      containers:
      - name: nginx2
        image: nginx
        ports:
        - containerPort: 80
        lifecycle:
          postStart:
            exec:
              command: ["/bin/sh", "-c", "echo Hello nginx2 > /usr/share/nginx/html/index.html"]

Deployment 3

piVersion: apps/v1
kind: Deployment
metadata:
  name: nginx3
spec:
  selector:
    matchLabels:
      run: nginx3
  replicas: 1
  template:
    metadata:
      labels:
        run: nginx3
        app: frontend3
    spec:
      containers:
      - name: nginx3
        image: nginx
        ports:
        - containerPort: 80
        lifecycle:
          postStart:
            exec:
              command: ["/bin/sh", "-c", "echo Hello nginx3 > /usr/share/nginx/html/index.html"]

Service 1

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: frontend
spec:
  ports:
  - name: http
    port: 80
    protocol: TCP
  selector:
    app: frontend

Service 2

apiVersion: v1
kind: Service
metadata:
  name: nginx2
  labels:
    app: frontend2
spec:
  ports:
  - port: 80
    protocol: TCP
  selector:
    app: frontend2

Service 3

apiVersion: v1
kind: Service
metadata:
  name: nginx3
  labels:
    app: frontend3
spec:
  ports:
  - port: 80
    protocol: TCP
  selector:
    app: frontend3

Virtual Service

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: nginxvirt
spec:
  gateways:
  - mesh # traffic inside cluster
  - comp-ingress-gateway # traffic from outside cluster
  hosts:
  - nginx.default.svc.cluster.local
  - nginx.com # outside cluster
  - nginx3.default.svc.cluster.local
  - nginx2.default.svc.cluster.local
  http:
  - name: a
    match:
    - uri:
        prefix: /wagholi
      headers:
        location:
          exact: pune
    rewrite:
      uri: /
    route:
    - destination:
        host: nginx.default.svc.cluster.local
        port:
          number: 80
  - name: b
    match:
    - uri:
        prefix: /yerwada
      headers:
        location:
          exact: pune
    rewrite:
      uri: /
    route:
    - destination:
        host: nginx2.default.svc.cluster.local
        port:
          number: 80
  - name: c
    match:
    - uri:
       prefix: /hadasapar
      headers:
        location:
          exact: pune
    rewrite:
      uri: /
    route:
    - destination:
        host: nginx3.default.svc.cluster.local
        port:
          number: 80

Gateway

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: comp-ingress-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - hosts:
    - '*'
    port:
      name: http
      number: 80
      protocol: HTTP
  - hosts:
    - '*'
    port:
      name: https
      number: 443
      protocol: HTTPS
    tls:
      mode: SIMPLE
      privateKey: /etc/istio/ingressgateway-certs/tls.key
      serverCertificate: /etc/istio/ingressgateway-certs/tls.crt

Some ubuntu pod to test inside traffic

apiVersion: v1
kind: Pod
metadata:
  name: ubu1
spec:
  containers:
  - name: ubu1
    image: ubuntu
    command: ["/bin/sh"]
    args: ["-c", "apt-get update && apt-get install curl -y && sleep 3000"]

And the results:

Inside:

root@ubu1:/# curl -H "location: pune" nginx/wagholi
Hello nginx1
root@ubu1:/# curl -H "location: pune" nginx/hadasapar
Hello nginx3
root@ubu1:/# curl -H "location: pune" nginx/yerwada  
Hello nginx2

Outside:

curl -H "location: pune" -H "host: nginx.com" ingress_gateway_ip/hadasapar
Hello nginx3
curl -H "location: pune" -H "host: nginx.com" ingress_gateway_ip/wagholi
Hello nginx1
curl -H "location: pune" -H "host: nginx.com" ingress_gateway_ip/yerwada
Hello nginx2

EDIT

How Can I find ingress_gateway_ip?

You Can use

kubectl get svc istio-ingressgateway -n istio-system

And it's istio-ingressgateway EXTERNAL-IP

If the EXTERNAL-IP value is set, your environment has an external load balancer that you can use for the ingress gateway. If the EXTERNAL-IP value is (or perpetually ), your environment does not provide an external load balancer for the ingress gateway. In this case, you can access the gateway using the service’s node port.


Can I do differently Ingress for each service and then map to VirtualService.

I'm not sure about that but i think it's possible. Check below links

I hope it will help You. Let me know if You have any more questions.

-- jt97
Source: StackOverflow