19

I have a simple ingress network, I want to access services at different namespaces, from this ingress network.

How I can do this? My ingress network yaml file:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress
spec:
  rules:
 - host: api.myhost.com
 http:
 paths:
  - backend:
      serviceName: bookapi-2
      servicePort: 8080
    path: /booking-service/

I've set the ExternalNames service type to the yaml file:

 apiVersion: v1
 kind: Service
 metadata:
   name: bookapi-2
   namespace: booking-namespace
 spec:
   type: ExternalName
   externalName: bookapi-2
   ports:
     - name: app
     protocol: TCP
      port: 8080
      targetPort: 8080
   selector:
      app: bookapi-2
      tier: backend-2
aurelius
  • 3,433
  • 1
  • 13
  • 22
ColossusMark1
  • 1,189
  • 4
  • 14
  • 27
  • There's a good demo in https://github.com/ProProgrammer/cross-namespace-nginx-ingress-kubernetes which is linked from https://github.com/kubernetes/kubernetes/issues/17088 but I don't know if you've happy to use nginx ingress – Ryan Dawson Aug 16 '18 at 14:00

4 Answers4

40

An ExternalName service is a special case of service that does not have selectors and uses DNS names instead.

You can find out more about ExternalName service from the official Kubernetes documentation:

When you want to access a service from a different namespace, your yaml could, for example, look like this:

kind: Service
apiVersion: v1
metadata:
  name: test-service-1
  namespace: namespace-a
spec:
  type: ExternalName
  externalName: test-service-2.namespace-b.svc.cluster.local
  ports:
  - port: 80

As to your Ingress yaml file, please recheck it and make sure it is compliant with the official examples, for example this one as it contains some inconsistency:

apiVersion: extensions/v1beta1  
kind: Ingress  
metadata:  
  name: my-ingress  
spec:  
  rules:  
  - host: www.mysite.com  
    http:  
      paths:  
      - backend:  
          serviceName: website  
          servicePort: 80  
  - host: forums.mysite.com  
    http:  
      paths:  
      - path:  
        backend:  
          serviceName: forums  
          servicePort: 80

Please also recheck ExternalName yaml as it has TargetPorts and selectors which are not used in this type of Service and make sure that:

ExternalName Services are available only with kube-dns version 1.7 and later.

In case you will not succeed, please share the kind of problem you have meet.

aurelius
  • 3,433
  • 1
  • 13
  • 22
  • 3
    Just in case it helps a future reader: when I run `kubectl describe ingress` I see an error saying that no endpoints are found for the ExternalName Service. Things work just fine though. (On microk8s, for `externalName: kubernetes-dashboard.kube-system.svc.cluster.local`.) – Arjan Apr 13 '20 at 16:47
  • 1
    @Arjan I get error `service "default/service-name" is type "ExternalName", expected "NodePort" or "LoadBalancer"` and it doesn't work. Did you do something different else? – Lukas Sep 23 '20 at 10:46
  • @aurelis Didn't work. get this error: `Translation failed: invalid ingress spec: service "hello/nginx-external" is type "ExternalName", expected "NodePort" or "LoadBalancer"` – Abu Shumon Apr 01 '21 at 12:27
  • 2
    First, did you really mean to point the Ingress to the "external" service `test-service-1` which is pointing to another service in a different namespace? I am not sure if you really meant this as your Ingress is pointing to completely different service names... Anyway, on GKE, this setup is not working as it requires healthcheck on the backend service and it always fails for the external service (it's configured properly and manually tested). – Martin Grůber Jun 15 '21 at 05:25
6
  1. create namespace service-ns
  2. create a service of type ClusterIP ( which is default ) named nginx-service listening on port 80 in namespace service-ns
  3. create nginx deployment in service-ns
  4. create namespace ingress-ns
  5. create a service in ingress-ns of type ExternalName and pointing to FQDN of nginx-service pointing it as nginx-internal.service-ns.svc.cluster.local
  6. create ingress rules

NOTE: Demo code not to be running in production. Just wanted to give an idea of how it would work cross-namespaces

---
#1
apiVersion: v1
kind: Namespace
metadata:
  name: service-ns
---
#2
apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx
  name: nginx-internal
  namespace: service-ns
spec:
  ports:
  - name: "80"
    port: 80
    targetPort: 80  
  selector:
    app: nginx
---
#3
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
  namespace: service-ns
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        image: nginx
        name: nginx
        ports:
        - containerPort: 80
      restartPolicy: Always
---
#4
apiVersion: v1
kind: Namespace
metadata:
  name: ingress-ns
---
#5
kind: Service
apiVersion: v1
metadata:
  name: nginx
  namespace: ingress-ns
spec:
  type: ExternalName
  externalName: nginx-internal.service-ns.svc.cluster.local
  ports:
  - port: 80
---
#6
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: main-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
  namespace: ingress-ns    
spec:
  rules:
    - host: whatever.domain.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: nginx
                port:
                  number: 80
Rohit Salecha
  • 893
  • 11
  • 9
3

Outside traffic comes through ingress controller service that is responsible for routing the traffic based on the defined routing rules or what we call ingress rules in k8s world.

In other words, ingress resources are just routing rules (think of it in away that's similar to DNS records) so when you define an ingress resource you just defined a rule for ingress controller to work on and route traffic based on such defined rules.

Solution:

  1. Since Ingress are nothing but routing rules, you could define such rules anywhere in the cluster (in any namespace) and controller should pick them up as it monitors creation of such resources and react accordingly.

    Here's how to create ingress easily using kubectl

    Create an ingress

    kubectl create ingress <name> -n namespaceName --rule="host/prefix=serviceName:portNumber"

    Note: Add --dry-run=client -oyaml to generate yaml manifest file

  2. Or you may create a service of type ExternalName in the same namespace where you have defined your ingress. such external service can point to any URL (a service that lives outside namespace or even k8s cluster)

    Here's an example:

    Create an ExternalName service

    kubectl create service externalname ingress-ns -n namespaceName --external-name=serviceName.namespace.svc.cluster.local --tcp=80:80

Note: Add --dry-run=client -oyaml to generate yaml manifest file

kind: Service
apiVersion: v1
metadata:
  name: nginx
  namespace: ingress-ns
spec:
  type: ExternalName
  externalName: serviceName.namespace.svc.cluster.local #or any external svc
  ports:
  - port: 80 #specify the port of service you want to expose 
    targetPort: 80 #port of external service 

As described above, create an ingress as below: kubectl create ingress <name> -n namespaceName --rule="host/prefix=serviceName:portNumber"

Note: Add --dry-run=client -oyaml to generate yaml manifest file

Muhammad Soliman
  • 21,644
  • 6
  • 109
  • 75
1

ExternaNames service should be created without any selector options. So create the ExternaNames service in the namespace where your ingress resource is created and point the external name service to resolve the name of your application hosted in different namespace.

  • 2
    Hello and welcome to SO! Please read the [tour](https://stackoverflow.com/tour), and [How do I write a good answer?](https://stackoverflow.com/help/how-to-answer) For example you can add details and code snippet how can that be achieved. Take a look at the accepted answer as an example – Tomer Shetah Jan 09 '21 at 08:10