Exposing TCP and UDP based services in Istio - The Easy Way

Istio is pretty cool guys. It's manageable and super easy to use. One thing I come across to find out about Istio when considering exposing TCP and UDP services is that it opens ports 80 (HTTP), 443(HTTPS), and 15021 (health check) for the ingress gateway as default ones. Apart from that, it should be on us to configure when exposing other TCP or UDP ports when it's necessary. That being said, it's pretty similar when configuring to expose those new ports with an NGINX Ingress Controller (Check this blog).

Technical Guide

When we install or run the Istio service mesh in Kubernetes, we have objects created by default. In our case, we want to focus on this Service Object named istio-ingressgateway.

Let us see what shall we find when sending a get API query for the svc in our namespace called istio-system.

kubectl get svc -n istio-system
# This will give us list of service objects in our istio-system namespace
NAME                     TYPE           CLUSTER-IP     EXTERNAL-IP    PORT(S)                                                     AGE
istio-egressgateway      ClusterIP      10.0.254.114   <none>         80/TCP,443/TCP                                              1d
istio-ingressgateway     LoadBalancer   10.0.58.73     x.x.x.x   15021:30890/TCP,80:30850/TCP,443:30560/TCP                  1d
istiod                   ClusterIP      10.0.129.213   <none>         15010/TCP,15012/TCP,443/TCP,15014/TCP                       1d

You can see that our istio-ingressgateway has ports 80, 443 & 15021 opened. Let us modify that svc and manage to add other TCP or UDP-based ports. As for this example, I'll go ahead and add port 6379 for the default Redis port.

To edit:

KUBE_EDITOR="nano" kubectl edit svc -n istio-system istio-ingressgateway
# Add this for within the ports section of the svc.
...
- name: redis
  port: 6379
  protocol: TCP #can be also UDP for udp service
  targetPort: 6379
 ...

Once saved we can go ahead and see if it has mapped a port to it, like so:

 $ kubectl get svc -n istio-system istio-ingressgateway
 # Will give us
NAME                   TYPE           CLUSTER-IP   EXTERNAL-IP    PORT(S)                                                     AGE
istio-ingressgateway   LoadBalancer   10.0.58.73   x.x.x.x   15021:30890/TCP,80:30850/TCP,443:30560/TCP,6379:30446/TCP   1d

You can see that it has opened port 6379(TCP) and started to listen.

Next Step

After we configured our ingress svc object for our Istio, we should modify our gateway(load balancer) object to also handle incoming traffic for our protocol (TCP/UDP):

KUBE_EDITOR="nano" kubectl edit gateway -n istio-system myGateway
# add this config to the section of 'servers' in the yaml.
....
- hosts:
    - redis.yourdomain.com
    port:
      name: redis-port
      number: 6379
      protocol: TCP
....

Final Configuration

Finally, we shall configure our virtualservice object of Istio.

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: redis
  namespace: istio-system
spec:
  gateways:
  - myGateway
  hosts:
  - redis.yourdomain.com
  tcp:
  - match:
    - port: 6379
    route:
    - destination:
        host: your-service-object-in-the-cluster
        port:
          number: 6379

easy-peasy, right!