<p>This question is about my inability to connect a gRPC client to a gRPC service hosted in Kubernetes (AWS EKS), with an Istio ingress gateway.</p>
<p><strong>On the kubernetes side:</strong> I have a container with a Go process listening on port 8081 for gRPC. The port is exposed at the container level. I define a kubernetes service and expose 8081. I define an istio gateway which selects istio: ingressgateway and opens port 8081 for gRPC. Finally I define an istio virtualservice with a route for anything on port 8081.</p>
<p><strong>On the client side:</strong> I have a Go client which can send gRPC requests to the service.</p>
<ul>
<li>It works fine when I <code>kubectl port-forward -n mynamespace service/myservice 8081:8081</code> and call my client via <code>client -url localhost:8081</code>.</li>
<li>When I close the port forward, and call with <code>client -url [redacted]-[redacted].us-west-2.elb.amazonaws.com:8081</code> my client fails to connect. (That url is the output of <code>kubectl get svc istio-ingressgateway -n istio-system -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'</code> with <code>:8081</code> appended.</li>
</ul>
<p><strong>Logs:</strong></p>
<ul>
<li>I looked at the <code>istio-system/istio-ingressgateway</code> service logs. I do not see an attempted connection.</li>
<li>I do see the bookinfo connections I made earlier when going over the <a href="https://istio.io/latest/docs/setup/getting-started/#ip" rel="nofollow noreferrer">istio bookinfo</a> tutorial. That tutorial worked, I was able to open a browser and see the bookinfo product page, and the ingressgateway logs show <code>&quot;GET /productpage HTTP/1.1&quot; 200</code>. So the Istio ingress-gateway works, it's just that I don't know how to configure it for a new gRPC endpoint.</li>
</ul>
<p><strong>Istio's Ingress-Gateway</strong></p>
<pre><code>kubectl describe service -n istio-system istio-ingressgateway
</code></pre>
<p>outputs the following, which I suspect is the problem, port 8081 is not listed despite my efforts to open it. I'm puzzled by how many ports are opened by default, I didn't open them (comments on how to close ports I don't use would be welcome but aren't the reason for this SO question)</p>
<pre><code>Name:                     istio-ingressgateway
Namespace:                istio-system
Labels:                   [redacted]
Annotations:              [redacted]
Selector:                 app=istio-ingressgateway,istio=ingressgateway
Type:                     LoadBalancer
IP:                       [redacted]
LoadBalancer Ingress:     [redacted]
Port:                     status-port  15021/TCP
TargetPort:               15021/TCP
NodePort:                 status-port  31125/TCP
Endpoints:                192.168.101.136:15021
Port:                     http2  80/TCP
TargetPort:               8080/TCP
NodePort:                 http2  30717/TCP
Endpoints:                192.168.101.136:8080
Port:                     https  443/TCP
TargetPort:               8443/TCP
NodePort:                 https  31317/TCP
Endpoints:                192.168.101.136:8443
Port:                     tcp  31400/TCP
TargetPort:               31400/TCP
NodePort:                 tcp  31102/TCP
Endpoints:                192.168.101.136:31400
Port:                     tls  15443/TCP
TargetPort:               15443/TCP
NodePort:                 tls  30206/TCP
Endpoints:                192.168.101.136:15443
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   &lt;none&gt;
</code></pre>
<p>So I think I did not properly open port 8081 for GRPC. What other logs or test can I run to help identify where this is coming from?</p>
<p>Here is the relevant yaml:</p>
<p><strong>Kubernetes Istio virtualservice:</strong> whose intent is to route anything on port 8081 to myservice</p>
<pre><code>apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: myservice
  namespace: mynamespace
spec:
  hosts:
  - &quot;*&quot; 
  gateways:
  - myservice
  http:
  - match:
    - port: 8081
    route:
    - destination:
        host: myservice
</code></pre>
<p><strong>Kubernetes Istio gateway:</strong> whose intent is to open port 8081 for GRPC</p>
<pre><code>apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: myservice
  namespace: mynamespace
spec:
  selector:
    istio: ingressgateway 
  servers:
    - name: myservice-plaintext
      port:
        number: 8081
        name: grpc-svc-plaintext
        protocol: GRPC
      hosts:
      - &quot;*&quot;
</code></pre>
<p><strong>Kubernetes service:</strong> showing port 8081 is exposed at the service level, which I confirmed with the port-forward test mentioned earlier</p>
<pre><code>apiVersion: v1
kind: Service
metadata:
  name: myservice
  namespace: mynamespace
  labels:
    app: myservice
spec:
  selector:
    app: myservice
  ports:
    - protocol: TCP
      port: 8081
      targetPort: 8081
      name: grpc-svc-plaintext
</code></pre>
<p><strong>Kubernetes deployment:</strong> showing port 8081 is exposed at the container level, which I confirmed with the port-forward test mentioned earlier</p>
<pre><code>apiVersion: apps/v1
kind: Deployment
metadata:
  name: myservice
  namespace: mynamespace
  labels:
    app: myservice
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myservice
  template:
    metadata:
      labels:
        app: myservice
    spec:
      containers:
      - name: myservice
        image: [redacted]
        ports:
        - containerPort: 8081
</code></pre>
<p><strong>Re checking DNS works on the client:</strong></p>
<pre><code>getent hosts [redacted]-[redacted].us-west-2.elb.amazonaws.com
</code></pre>
<p>outputs 3 IP's, I'm assuming that's good.</p>
<pre><code>[IP_1 redacted]  [redacted]-[redacted].us-west-2.elb.amazonaws.com
[IP_2 redacted]  [redacted]-[redacted].us-west-2.elb.amazonaws.com
[IP_3 redacted]  [redacted]-[redacted].us-west-2.elb.amazonaws.com
</code></pre>
<p><strong>Checking Istio Ingressgateway's routes:</strong></p>
<pre><code>istioctl proxy-status istio-ingressgateway-[pod name]
istioctl proxy-config routes istio-ingressgateway-[pod name]
</code></pre>
<p>returns</p>
<pre><code>Clusters Match
Listeners Match
Routes Match (RDS last loaded at Wed, 23 Sep 2020 13:59:41)

NOTE: This output only contains routes loaded via RDS.
NAME          DOMAINS     MATCH                  VIRTUAL SERVICE
http.8081     *           /*                     myservice.mynamespace
              *           /healthz/ready*        
              *           /stats/prometheus*
</code></pre>
<p>Port 8081 is routed to myservice.mynamespace, seems good to me.</p>
<p><strong>UPDATE 1:</strong>
I am starting to understand I can't open port 8081 using the default istio ingress gateway. That service does not expose that port, and I was assuming creating a gateway would update the service &quot;under the hood&quot; but that's not the case.
The external ports that I can pick from are: 80, 443, 31400, 15443, 15021 and I think my gateway needs to rely only on those. I've updated my gateway and virtual service to use port 80 and the client then connects to the server just fine.</p>
<p>That means I have to differentiate between multiple services not by port (can't route from the same port to two services obviously), but by SNI, and I'm unclear how to do that in gRPC, I'm guessing I can add a <code>Host:[hostname]</code> in the gRPC header. Unfortunately, if that's how I can route, it means headers need to be read on the gateway, and that mandates terminating TLS at the gateway when I was hoping to terminate at the pod.</p>

<blockquote>
<p>I am starting to understand I can't open port 8081 using the default istio ingress gateway. That service does not expose that port, and I was assuming creating a gateway would update the service &quot;under the hood&quot; but that's not the case. The external ports that I can pick from are: 80, 443, 31400, 15443, 15021 and I think my gateway needs to rely only on those. I've updated my gateway and virtual service to use port 80 and the client then connects to the server just fine.</p>
</blockquote>
<p>I'm not sure how exactly did you try to add custom port for ingress gateway but it's possible.</p>
<p>As far as I checked <a href="https://stackoverflow.com/questions/56661765/how-to-add-custom-port-for-istio-ingress-gateway">here</a> it's possible to do in 3 ways, here are the options with links to examples provided by @A_Suh, @Ryota and @peppered.</p>
<ul>
<li><a href="https://stackoverflow.com/a/56669078/11977760">Kubectl edit</a></li>
<li><a href="https://stackoverflow.com/a/58062314/11977760">Helm</a></li>
<li><a href="https://stackoverflow.com/a/61228394/11977760">Istio Operator</a></li>
</ul>
<hr />
<p>Additional resources:</p>
<ul>
<li><a href="https://stackoverflow.com/questions/51835752/how-to-create-custom-istio-ingress-gateway-controller">How to create custom istio ingress gateway controller?</a></li>
<li><a href="https://stackoverflow.com/questions/56643594/how-to-configure-ingress-gateway-in-istio">How to configure ingress gateway in istio?</a></li>
</ul>
<hr />
<blockquote>
<p>That means I have to differentiate between multiple services not by port (can't route from the same port to two services obviously), but by SNI, and I'm unclear how to do that in gRPC, I'm guessing I can add a Host:[hostname] in the gRPC header. Unfortunately, if that's how I can route, it means headers need to be read on the gateway, and that mandates terminating TLS at the gateway when I was hoping to terminate at the pod.</p>
</blockquote>
<p>I see you have already create new question <a href="https://stackoverflow.com/questions/64037625/can-i-define-subdomains-for-a-classic-aws-elb-that-was-provisioned-by-istio">here</a>, so let's just move there.</p>
