Search code examples
kubernetesistio

Is there a way to proxy calls to an ExternalName service thanks to an Istio VirtualService?


In a project I'm currently working on, I'd like to create a DNS alias for a Kubernetes service located in another namespace. To do so, I created an ExternalName service such as the following:

kind: Service
apiVersion: v1
metadata:
  name: connector
  namespace: test
spec:
  type: ExternalName
  externalName: gateway.eventing.svc.cluster.local

So far, so good. When I request the 'connector' DNS, I successfully hit the external name, i.e. gateway.eventing.svc.cluster.local.

Now, I would like to add headers to all http requests sent to the connector ExternalName service, so I created an Istio VirtualService to do so:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: connector
  namespace: test
spec:
  hosts:
    - connector
    - connector.test.svc.cluster.local
 http:
   - match:
      - uri:
          prefix: /
      route:
        - destination:
            host: connector
            port:
              number: 80
#headers config ignored for brevity

The problem is that the VirtualService is never called. It seems it does not intercepts request made to the connector DNS or to its fully qualified name, i.e. connector.test.svc.cluster.local.

I figured, after reading the documentation, that this happens because the Istio VirtualService checks the service registry, and the ExternalName service is not part of it, it's just some kind of DNS alias.

I therefore attempted to create an Istio ServiceEntry such as the following:

apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: connector
  namespace: test
spec:
  hosts:
  - connector
  endpoints:
  - address: gateway.eventing.svc.cluster.local
  ports:
  - number: 80
    name: http
    protocol: HTTP
  location: MESH_INTERNAL
  resolution: DNS

It works, and I can see in Kiali that instead of calling the PassthroughCluster when requesting connector, it is the connector ServiceEntry which is called, which is to my understanding what should be happening.

However, my connector VirtualService is still not called. Why is that? Is there a way to make it happen?

If not, what can I do to alias in a given namespace (i.e. test) a service located in another (i.e. eventing) and proxy http request thanks to an Istio VirtualService?

Thanks in advance for your help!

EDIT:

Sidecar injection is enabled namespace-wide (i.e. test)


Solution

  • So, it turns out that all that was missing to make it work was to both specify and name the port on the ExternalName service.

    Here's the updated yaml:

    kind: Service
    apiVersion: v1
    metadata:
      name: connector
      namespace: test
    spec:
      type: ExternalName
      externalName: gateway.eventing.svc.cluster.local
      ports:
        - name: http
          port: 80
    
    ---
    
    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
      name: connector
      namespace: test
    spec:
      hosts:
        - connector
        - connector.test.svc.cluster.local
     http:
       - match:
          - uri:
              prefix: /
          route:
            - destination:
                host: connector
                port:
                  number: 80
    #headers config ignored for brevity
    

    Naming the port is absolutely required, as it lets Istio know of the application protocol to use, as defined by the VirtualService.

    No need to add a ServiceEntry, it will work with the BYON host specified in the VirtualService.

    Note that the answer supplied by @Christoph Raab works as well, but is unhappilly too verbose to be marked as my prefered answer.