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

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

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

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

<p>So what's the problem of it? Thanks for any tips!</p>

<p>Here is my <code>redis.yml</code></p>

<pre><code>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
</code></pre>

<p>Update:</p>

<p>This is how I request</p>

<pre><code>[root]# redis-cli -h redis.basic.svc.cluster.local -p 80
redis.basic.svc.cluster.local:80&gt; get Test
Error: Protocol error, got "H" as reply type byte
</code></pre>

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

<ol>
<li><p>The <code>hosts:</code> needs to be <code>"*"</code> as <code>TCP</code> protocol works only with <code>IP:PORT</code>. There are no headers in L4.</p></li>
<li><p>There needs to be <code>TCP</code> port <code>match</code> Your <code>VirtualService</code> that matches <code>GateWay</code>. I suggest to name it in a unique way and match <code>Deployment</code> port name.</p></li>
<li><p>I suggest avoiding using port <code>80</code> as it is already used in default ingress configuration and it could result in port conflict, so i changed it to <code>11337</code>.</p></li>
</ol>

<p>So Your <code>GateWay</code> should look something like this:</p>

<pre><code>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:
    - "*"
</code></pre>

<p>And Your <code>VirtualService</code> like this:</p>

<pre><code>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
</code></pre>

<p><em>Note that I removed namespaces for clarity.</em></p>

<p>Then add our custom port to default ingress gateway use the following command:</p>

<pre><code>kubectl edit svc istio-ingressgateway -n istio-system
</code></pre>

<p>And add following next other port definitions:</p>

<pre><code>- name: redis-port
  nodePort: 31402
  port: 11337
  protocol: TCP
  targetPort: 16379
</code></pre>

<hr>

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

<p>To get Your gateway external IP you can use:</p>

<pre><code>export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
</code></pre>

<pre><code>redis-cli -h $INGRESS_HOST -p 11337
</code></pre>

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

<p>Hope this helps.</p>
