How to expose redis to outside with istio sidecar?

1/17/2020

I'm using redis with k8s 1.15.0, istio 1.4.3, it works well inside the network.

However when I tryed to use the istio gateway and sidecar to expose it to outside network, it failed.

Then I removed the istio sidecar and just started the redis server in k8s, it worked.

After searching I added DestinationRule to the config, but it didn't help.

So what's the problem of it? Thanks for any tips!

Here is my redis.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
      - name: redis
        image: docker.io/redis:5.0.5-alpine
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 16379
          protocol: TCP
          name: redis-port
        volumeMounts:
        - name: redis-data
          mountPath: /data
        - name: redis-conf
          mountPath: /etc/redis
        command:
          - "redis-server"
        args:
          - "/etc/redis/redis.conf"
          - "--protected-mode"
          - "no"
      volumes:
        - name: redis-conf
          configMap:
            name: redis-conf
            items:
              - key: redis.conf
                path: redis.conf
        - name: redis-data
          nfs:
            path: /data/redis
            server: 172.16.8.34

---
apiVersion: v1
kind: Service
metadata:
  name: redis-svc
  labels:
    app: redis-svc
spec:
  type: ClusterIP
  ports:
  - name: redis-port
    port: 16379
    protocol: TCP
  selector:
    app: redis

---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: redis-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: tcp
      protocol: TCP
    hosts:
    - "redis.basic.svc.cluster.local"

---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: redis-svc
spec:
  host: redis-svc

---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: redis-vs
spec:
  hosts:
  - "redis.basic.svc.cluster.local"
  gateways:
  - redis-gateway
  tcp:
  - route:
    - destination:
        host: redis-svc.basic.svc.cluster.local
        port:
          number: 16379

Update:

This is how I request

[root]# redis-cli -h redis.basic.svc.cluster.local -p 80
redis.basic.svc.cluster.local:80> get Test
Error: Protocol error, got "H" as reply type byte
-- Woko
istio
kubernetes
redis

2 Answers

1/21/2020

There are few thing that need to be different in case of exposing TCP application with istio.

  1. The hosts: needs to be "*" as TCP protocol works only with IP:PORT. There are no headers in L4.

  2. There needs to be TCP port match Your VirtualService that matches GateWay. I suggest to name it in a unique way and match Deployment port name.

  3. I suggest avoiding using port 80 as it is already used in default ingress configuration and it could result in port conflict, so i changed it to 11337.

So Your GateWay should look something like this:

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: redis-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 11337
      name: redis-port
      protocol: TCP
    hosts:
    - "*"

And Your VirtualService like this:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: redis-vs
spec:
  hosts:
  - "*"
  gateways:
  - redis-gateway
  tcp:
  - match:
    - port: 11337
    route:
      - destination:
          host: redis-svc
          port:
            number: 16379

Note that I removed namespaces for clarity.

Then add our custom port to default ingress gateway use the following command:

kubectl edit svc istio-ingressgateway -n istio-system

And add following next other port definitions:

- name: redis-port
  nodePort: 31402
  port: 11337
  protocol: TCP
  targetPort: 16379

To access the exposed application use istio gateway external IP and port that we just set up.

To get Your gateway external IP you can use:

export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
redis-cli -h $INGRESS_HOST -p 11337

If Your istio-ingressgateway does not have external IP assigned, use one of Your nodes IP address and port 31402.

Hope this helps.

-- Piotr Malec
Source: StackOverflow

1/17/2020

Thanks for suren's answer.

But i think redis.basic.svc.cluster.local is outside DNS host to match by VirtualService, and VirtualService.host is route to service redis-svc with full namespace path.

Maybe not for that reason.

-- Leonard Woo
Source: StackOverflow