Discovery of external services between QA/PROD environments


#1

I have an app the depends on external service that is accessed via HTTPS url and is different for QA and PROD environments. The external service is not in Kubernetes and can’t be added using mesh expansion.

I’m trying to figure out if it’s possible to configure my app to talk to something like edition.apps.svc.cluster.local and to configure routing to a correct service for the environment in Istio. So, for test purposes, if my app is deployed to QA it would get routed to edition.cnn.com, and if in production it would be a different url, let’s say www.google.com. Essentially, I need to to arbitrary re-route an HTTP request to an external url.

I’ve tried to update the TLS originating example, but getting

“curl: (6) Could not resolve host: edition.apps.svc.cluster.local”

Example of my definitions:

apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: edition-cnn-com
spec:
  hosts:
  - edition.cnn.com
  ports:
  - number: 80
    name: http-port
    protocol: HTTP
  - number: 443
    name: http-port-for-tls-origination
    protocol: HTTP
  resolution: DNS
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: edition.default.svc.cluster.local
spec:
  hosts:
  - edition.default.svc.cluster.local
  http:
  - route:
    - destination:
        host: edition.cnn.com
        port:
          number: 443
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: edition-cnn-com
spec:
  hosts:
  - edition.cnn.com
  http:
  - match:
    - port: 80
    route:
    - destination:
        host: edition.cnn.com
        port:
          number: 443
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: edition-cnn-com
spec:
  host: edition.cnn.com
  trafficPolicy:
    loadBalancer:
      simple: ROUND_ROBIN
    portLevelSettings:
    - port:
        number: 443
      tls:
        mode: SIMPLE # initiates HTTPS when accessing edition.cnn.com

What am I missing? Or is there a different, better way to discover external services? I’ve read about using K8s service without selectors and providing Endpoints, but that leads to maintaining a constantly changing mapping of IP addresses to my service.


#2

I think you probably want a ServiceEntry without a VirtualService. The ServiceEntry adds a “fake” service to the service registry since you don’t have a real local service.

Could not resolve host: edition.apps.svc.cluster.local

This won’t resolve because it’s not a k8s service. Short of setting up a local dns server (which isn’t crazy) you might need to create a real k8s ClusterIP service so you can resolve the IP, then hijack it in istio. Another option is a real public DNS entry that resolves to a fake cluster IP that you can hijack in the ServiceEntry.


#3

yes, ServiceEntry adds a “fake” service record, but it doesn’t do routing, unlike K8s’ ExternalName Service (it’s CNAME in the end and doesn’t work with TLS in my experiments).

what do you mean by hijacking a ClusterIP service in Istio?


#4

Here’s a CoreDNS plugin and deployment that integrates with Istio to provide DNS for ServiceEntries. Out of the box it expects to integrate with K8s DNS by using the kube-dns ConfigMap to point DNS queries for a particular stub domain (global. by default) to the CoreDNS servers backed with Istio data (and would not work with your svc.cluster.local hostname since k8s controls that one). You could also configure those CoreDNS servers to be in the normal k8s DNS resolution chain since the kube-dns ConfigMap allows that as well.


#5

Zack, I’m not sure how istio-coredns-plugin solves my problem. As I understand, using istio-coredns-plugin I can map a fake domain to a cluster ip that will be resolved using CoreDNS? For example to map edition.cnn.com to 17.17.17.17 and refer to it like edition.cnn.com.global?

apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
spec:
  hosts:
  - edition.cnn.com
  addresses:
  - 17.17.17.17
  resolution: STATIC

If my understanding is correctly, I can do the same with native K8s service without selectors and endpoints and both solutions will have the same problem, that if an app is establishing a TLS connection to edition.cnn.com.global, and 17.17.17.17 responds with a cert for a different domain (as it always will), TLS connection won’t be established?