<p>I am using the Jaeger Operator to deploy the Jaeger Query and Collector services to Kubernetes (K3S actually) along with an ElasticSearch instance for the storage backend.</p>
<p>The Jaeger Operator creates an Ingress instance for the Jaeger Query service but it assumes that all of your Jaeger Agents will also be running inside the Kubernetes cluster. Unfortunately, that is not the case for me as some applications that I am tracing are not run within the cluster so I need my Jaeger Collector to be accessible from outside.</p>
<p><a href="https://github.com/jaegertracing/jaeger-operator/issues/1048" rel="nofollow noreferrer">This Jaeger GitHub issue discusses a potential enhancement to the Jaeger Operator for this functionality</a> and it suggests creating your own Ingress outside of the Operator to expose the Jaeger Collector but doesn't go into details.</p>
<p>I also want to utilize gRPC for the communication between the Agent outside the cluster and the Collector in the cluster and <a href="https://github.com/kubernetes/ingress-nginx/tree/master/docs/examples/grpc#grpc" rel="nofollow noreferrer">this article describes how to set up an Ingress for gRPC</a> (though it is not specific to Jaeger). I used the <a href="https://github.com/kubernetes/ingress-nginx/blob/master/docs/examples/grpc/ingress.yaml" rel="nofollow noreferrer">example ingress spec there</a>, made some tweaks for my scenario, and deployed it to my cluster:</p>
<pre><code>apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: &quot;nginx&quot;
    nginx.ingress.kubernetes.io/ssl-redirect: &quot;true&quot;
    nginx.ingress.kubernetes.io/backend-protocol: &quot;GRPC&quot;
  name: simple-prod-collector
  namespace: monitoring
spec:
  rules:
  - host: jaeger-collector.my-container-dev
    http:
      paths:
      - backend:
          serviceName: simple-prod-collector
          servicePort: 14250
</code></pre>
<p>This creates an Ingress for me alongside the simple-prod-query ingress that is created by the Jaeger Operator:</p>
<pre><code>NAMESPACE      NAME                    CLASS    HOSTS                               ADDRESS          PORTS   AGE
monitoring    simple-prod-query       &lt;none&gt;   jaeger-query.my-container-dev       10.128.107.220   80      6h56m
monitoring    simple-prod-collector   &lt;none&gt;   jaeger-collector.my-container-dev                    80      4h33m
</code></pre>
<p>Here are the services behind the ingress:</p>
<pre><code>NAMESPACE        NAME                             TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)                                  AGE
monitoring       simple-prod-collector            ClusterIP      10.43.20.131    &lt;none&gt;           9411/TCP,14250/TCP,14267/TCP,14268/TCP   7h5m
monitoring       simple-prod-query                ClusterIP      10.43.141.211   &lt;none&gt;           16686/TCP                                7h5m
monitoring       simple-prod-collector-headless   ClusterIP      None            &lt;none&gt;           9411/TCP,14250/TCP,14267/TCP,14268/TCP   7h5m
</code></pre>
<p>Unfortunately, my Jaeger Agent can't seem to speak to it still... I am actually deploying my Jaeger Agent via docker-compose and as you can see here, I am configuring it to connect to jaeger-collector.my-container-dev:80:</p>
<pre><code>version: &quot;3&quot;

services:

  jaeger-agent:
    image: jaegertracing/jaeger-agent
    hostname: jaeger-agent
    command: [&quot;--reporter.grpc.host-port=jaeger-collector.my-container-dev:80&quot;]
    ports:
      - &quot;6831:6831/udp&quot;  # UDP | accept jaeger.thrift in compact Thrift protocol used by most current Jaeger clients
      - &quot;5778:5778&quot;      # HTTP | serve configs, sampling strategies
      - &quot;14271:14271&quot;    # HTTP | admin port: health check at / and metrics at /metrics
    restart: on-failure
</code></pre>
<p>I can see that something is wrong with the connection because when I hit the Jaeger Agent's Sampling Strategy service with an <code>HTTP GET to http://localhost:5778/sampling?service=myservice</code>, I get an error back that says the following:</p>
<pre><code>collector error: rpc error: code = Unimplemented desc = Not Found: HTTP status code 404; transport: received the unexpected content-type &quot;text/plain; charset=utf-8&quot;
</code></pre>
<p>Is there something wrong with my Ingress spec? No trace data seems to be making it from my Agent to the Collector and I get errors when hitting the Jaeger Agent Sampling Service. Also, I find it a little strange that there is no IP Address listed in the <code>kubectl get ing</code> output but perhaps that is a red herring.</p>
<p>As mentioned above, I am using K3S which seems to use traefik for its ingress controller (as opposed to nginx). I checked the logs for the traefik controller and I didn't see anything helpful there either.</p>

BearsEars
<p>OK, I figured out the issue here which may be obvious to those with more expertise. <a href="https://github.com/kubernetes/ingress-nginx/tree/master/docs/examples/grpc#grpc" rel="nofollow noreferrer">The guide I linked to above that describes how to make an Ingress spec for gRPC</a> is specific to NGINX. Meanwhile, I am using K3S which came out of the box with Traefik as the Ingress Controller. Therefore, the annotations I used in my Ingress spec had no affect:</p>
<pre><code>metadata:
  annotations:
    kubernetes.io/ingress.class: &quot;nginx&quot;
    nginx.ingress.kubernetes.io/ssl-redirect: &quot;true&quot;
    nginx.ingress.kubernetes.io/backend-protocol: &quot;GRPC&quot;
</code></pre>
<p>So I found <a href="https://stackoverflow.com/questions/54562993/traefik-as-an-ingress-controller-server-grpc-unknown-no-status-received">another Stack Overflow post discussing Traefik and gRPC</a> and modified my original Ingress spec above a bit to include the annotations mentioned there:</p>
<pre><code>apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: simple-prod-collector
  namespace: monitoring
  annotations:
    kubernetes.io/ingress.class: traefik
    ingress.kubernetes.io/protocol: h2c
    traefik.protocol: h2c
spec:
  rules:
  - host: jaeger-collector.my-container-dev
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: simple-prod-collector
            port:
              number: 14250
</code></pre>
<p>These are the changes I made:</p>
<ol>
<li>Changed the <code>metadata/annotations</code> (this was the actual change needed I am sure)</li>
<li>I also updated the spec version to use <code>networking.k8s.io/v1</code> instead of <code>networking.k8s.io/v1beta1</code> so there are some structural changes due to that but none of the actual content changed AFAIK.</li>
</ol>
<p>Hopefully this helps someone else running into this same confusion.</p>
