Match Istio Virtual Services routes for different paths on same port

8/14/2019

I'm wondering how I can match gRPC routes on the same port. Here's an example of what I was hoping to accomplish with my VirtualService:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: istio-ingress
spec:
  hosts:
  - "*"
  gateways:
  - istio-gateway
  http:
  - match:
    - uri:
      prefix: "/custom.api/stream"
    - port: 31400
    route:
    - destination:
        host: stream-handler.default.svc.cluster.local
        port:
          number: 8444
    timeout: 60s
    retries:
      attempts: 3
      perTryTimeout: 2s
  - match:
    - port: 31400
    route:
    - destination:
        host: api.default.svc.cluster.local
        port:
          number: 8443
    timeout: 60s
    retries:
      attempts: 3
      perTryTimeout: 2s

So basically: for all requests into 31400 the first match looks for requests to stream at "/custom.api/stream" which has a destination of my stream server.

The second rule as a catch all to gain entry to my main API.

My goal is to have all connections coming through 31400 and then splinter off the request to a dedicated internal service. In the future I'll likely split off services even further (not just for streaming). ie. entire groups of the endpoint might be handled by separate clusters.

When I deploy this rule though the whole VS seems to fail and nothing responds.

-- ddibiase
istio
kubernetes

2 Answers

8/30/2019

Here are my observations:

  1. VirtualService -> http.match.port. I don't think port is used correctly here. If this is supposed to indicate the listening to incoming requests to port 31400, then this should actually be in the Gateway YAML specification istio-gateway.
  2. Please share the specification of your Gateway named istio-gateway. Basically, it is there where you specify that you are listening to port.number: 31400. The VirtualService is where you indicate to which service/host and port you want to route or "splinter off the request".

Please check and see if it helps.

-- mOchi
Source: StackOverflow

8/27/2019

Ports are externally exposed in the Ingressgateway and should be internally configured using a Gateway. The VirtualService is intended for layer 7 routing only (once attached to a Gateway).

In your match configuration, you're specifying that the addressed host should receive requests in the port 31400, not that the service is listening there. From the documentation:

port: Specifies the ports on the host that is being addressed. Many services only expose a single port or label ports with the protocols they support, in these cases it is not required to explicitly select the port.

In your case, you might want to create a new Gateway to take care of the exposed port's configuration and then, attach the routing part using your VirtualService:

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: grpc-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 31400
      name: grpc
      protocol: GRPC
    hosts:
    - "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: grpc-virtualservice
spec:
  hosts:
  - "*"
  gateways:
  - grcp-gateway
  http:
  - match:
    - uri:
      exact: "/custom.api/stream"
    route:
    - destination:
        host: stream-handler.default.svc.cluster.local
        port:
          number: 8444
    timeout: 60s
    retries:
      attempts: 3
      perTryTimeout: 2s
  - match:
    - uri:
      prefix: "/"
    route:
    - destination:
        host: api.default.svc.cluster.local
        port:
          number: 8443
    timeout: 60s
    retries:
      attempts: 3
      perTryTimeout: 2s

Since match cannot be empty, you need to prefix it to pick up whatever is coming except for the previous URI exact match.

-- yyyyahir
Source: StackOverflow