kubernetestcpcloudload-balancingistio-gateway

Is it possible route multiple TCP-based services by domain with single load balancer using Istio?


I have k8s cluster with Istio ingress controller installed. And load balancer has its external IP assigned by cloud provider.

Inside cluster, I made 2 deployments that runs database and web server, respectively. (Note that database is not important. it can be any TCP-based service.)

For web server, there are bunch of examples routing HTTP and HTTPS for Istio VirtualService and Gateway, So I could made it work easily.

And this is what I'd like to ask.

Can I route TCP similar to HTTP one does, based on domain? As far as I know, this cannot be done simply because TCP is not working like that.

I'm asking this because I have advise that this is possible using Istio. True or not, following to advice, the figure below is what I want to see, if it really works.

+-------------+                                                 +---------+  +------------+
| A.my.domain |--+                                           +--| Service |--| MariaDB #1 |
+-------------+  |  +----+  +---------+  +----------------+  |  +---------+  +------------+
                 +--| LB |--| Gateway |--| VirtualService |--+
+-------------+  |  +----+  +---------+  +----------------+  |  +---------+  +------------+
| B.my.domain |--+                                           +--| Service |--| MariaDB #2 |
+-------------+                                                 +---------+  +------------+

Let say there are multiple TCP-based services receive traffics through single load balancer on same port. Since I've mentioned service as DB, assume that load balancer have listener for 3306 port.

Also, I have my.domain with NS records given by cloud provider configured. So I can map whatever into like A.my.domain, B.my.domain. Both domains are mapped with same load balancer IP for A record. (Or, random-generated super long domain for CNAME record.)

If user connect with A.my.domain:3306, then it must reach to MariaDB #1 and for B.my.domain:3306 must reach to MariaDB #2.

As mentioned, my opinion is this is impossible but I'm being said that I can use host field, which makes me doubt.

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: product-gw
  namespace: product-ns
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 3306
      name: tcp-mariadb
      protocol: TCP
    hosts:
    - "*"              # Does it mean that I can use this for my purpose?
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: product-vs
  namespace: product
spec:
  hosts:
  - "*"                # And this one?
  gateways:
  - product-gw
  tcp:
  - match:
    - port: 3306
    route:
    - destination:
        host: product-db-1.product.svc.cluster.local
        port:
          number: 3306
...

I've done some searching and trial-and-error. Or, as other option, I thought 'do I have to make multiple load balancers with new IP whenever new services are deployed by namespace?', though I'm not sure this is common approach for cloud service.

Any advice would be appreciated.


Solution

  • The domain is not a property of TCP but is only used to lookup the IP address. In the TCP traffic only the IP address can be seen but not the domain name - unless it is specifically included as part of an application protocol like in HTTP.

    Therefore it is impossible to balance arbitrary TCP traffic on the same IP addressed based on the domain the client might have intended to access the IP address - the information necessary to do this does not exist.