Service located in another namespace
Asked Answered
G

7

279

I have been trying to find a way to define a service in one namespace that links to a Pod running in another namespace. I know that containers in a Pod running in namespaceA can access serviceX defined in namespaceB by referencing it in the cluster DNS as serviceX.namespaceB.svc.cluster.local, but I would rather not have the code inside the container need to know about the location of serviceX. That is, I want the code to just lookup serviceX and then be able to access it.

The Kubernetes documentation suggests that this is possible. It says that one of the reasons that you would define a service without a selector is that You want to point your service to a service in another Namespace or on another cluster.

That suggests to me that I should:

  1. Define a serviceX service in namespaceA, without a selector (since the POD I want to select isn't in namespaceA).
  2. Define a service (which I also called serviceX) in namespaceB, and then
  3. Define an Endpoints object in namespaceA to point to serviceX in namespaceB.

It is this third step that I have not been able to accomplish.

First, I tried defining the Endpoints object this way:

kind: Endpoints
apiVersion: v1
metadata:
  name: serviceX
  namespace: namespaceA
subsets:
  - addresses:
      - targetRef:
          kind: Service
          namespace: namespaceB
          name: serviceX
          apiVersion: v1
    ports:
      - name: http
        port: 3000

That seemed the logical approach, and obviously what the targetRef was for. But, this led to an error saying that the ip field in the addresses array was mandatory. So, my next try was to assign a fixed ClusterIP address to serviceX in namespaceB, and put that in the IP field (note that the service_cluster_ip_range is configured as 192.168.0.0/16, and 192.168.1.1 was assigned as the ClusterIP for serviceX in namespaceB; serviceX in namespaceA was auto assigned a different ClusterIP on the 192.168.0.0/16 subnet):

kind: Endpoints
apiVersion: v1
metadata:
  name: serviceX
  namespace: namespaceA
subsets:
  - addresses:
        - ip: 192.168.1.1
          targetRef:
            kind: Service
            namespace: namespaceB
            name: serviceX
            apiVersion: v1
    ports:
      - name: http
        port: 3000

That was accepted, but accesses to serviceX in namespaceA did not get forwarded to the Pod in namespaceB - they timed out. Looking at the iptables setup, it looks like it would have had to do NAT pre-routing twice to accomplish that.

The only thing I did find that worked - but is not a satisfactory solution - is to lookup the actual IP address of the Pod providing serviceX in namespaceB and put that address in the Endpoints object in namespaceA. That isn't satisfactory, of course, because the Pod IP address may change over time. That's the problem service IPs are there to solve.

So, is there a way to meet what seems to be the promise of the documentation that I can point a service in one namespace to a service running in a different namespace?

A commenter questioned why you would want to do this - here is a use case that makes sense to me, at least:

Say you have a multi-tenant system, which also includes a common data-access function that can be shared between tenants. Now imagine that there are different flavors of this data-access function with common APIs, but different performance characteristics. Some tenants get access to one of them, other tenants have access to another one.

Each tenant's pods run in their own namespaces, but each one needs to access one of these common data-access services, which will necessarily be in another namespace (since it is accessed by multiple tenants). But, you wouldn't want the tenant to have to change their code if their subscription changes to access the higher-performing service.

A potential solution (the cleanest one I can think of, if only it worked) is to include a service definition in each tenant's namespace for the data-access service, with each one configured for the appropriate endpoint. This service definition would be configured to point to the proper data-access service each tenant is entitled to use.

Germiston answered 14/5, 2016 at 1:22 Comment(8)
the point of namespaces is to isolate, so i think if you need to go across namespaces you need to know at least where it is located!Energumen
So, what does the documentation mean when it suggests you can direct a service defined in one namespace to access a service in a different namespace by not defining a selector - and by implication defining an endpoint? There are certainly valid use cases for this - one of which I added to the question. Is the documentation just misleading, or is there a way to do it that I have not yet figured out?Germiston
i'm not sure, sorry. what i know is that i access services in multiple namespaces using their fqdn. I do this especially with vpn, since i have 1 vpn pod and i connect through all services from it. however you need to know the namespace and provide fqdn. i would suggest you ask on the slack channel.Energumen
Using fqdn is the solution I'm currently using. My use case would be better served, though, (now added to question) if that wasn't necessary.Germiston
I also wonder what the documentation is referring too, however I can use fqdn as a satisfactory solution for my use case.Chord
I need to do the exact opposite! Prevent namespace traversal.Neocolonialism
I found a working video : youtu.be/TikEgvwhdJ8Squill
@Neocolonialism Use a Network Policy? kubernetes.io/docs/concepts/services-networking/…Destinee
T
512

I stumbled over the same issue and found a nice solution which does not need any static ip configuration:

You can access a service via it's DNS name (as mentioned by you): servicename.namespace.svc.cluster.local

You can use that DNS name to reference it in another namespace via a local service:

kind: Service
apiVersion: v1
metadata:
  name: service-y
  namespace: namespace-a
spec:
  type: ExternalName
  externalName: service-y.namespace-b.svc.cluster.local
  ports:
  - port: 80
Teece answered 2/6, 2017 at 12:53 Comment(11)
This is a great solution! I'm not sure if the "ExternalName" type was available for services when I originally asked the question, but it is supported now, and neatly solves the problem. Thanks, Paul.Germiston
Does this work? i doubt. can anyone confirm if this really worked, does not work for me.Latter
Yes it does. It works for one pod to talk to a service in another namespace, but not for an ingress loadbalancer.Teece
because of fix kubernetes in-cluster CNAME lookup, old version maybe not work.Invariant
Would/should this work for services in the kube-system namespace too?Viyella
Due to this bug it does not work in kubernetes 1.11.5.Hotien
Note: this solution only worked for us in case where the names of service-x and service-y were equal!Messer
Does this solution work with kubernetes discovery service? #59157947Organon
Does this work with the kube system namespace ? @TeeceGrig
This does not seem to work in OpenShift 4 with default network settings. I tried this in a route with docs.openshift.com/container-platform/4.11/networking/routes/… this enabled, without success. I can reach podA in NS-A from pod B in NS-B with curl but in a service or a route. Application: a namespace serving a maintenance page and routes pointing to it.Pourparler
tried this implementation for kafka wheren cluster is in one namespace and tried to access it from another one. Access part is fine but when we go for put of messages its failing. Any idea/ any suggestion is someone is tried this.Kincaid
I
78

It is so simple to do it.

<service.name>.<namespace name>.svc.cluster.local or <service.name>.<namespace name>

HTTP/HTTPS across namespace ref : http://<service-name>.<namespace-name>.svc.cluster.local

If you want to use it as a host and want to resolve it,

                Use : <service name> (Use if in same namespace)
                Use : <service.name>.<namespace name> (Use if across namespace)
                Use : <service.name>.<namespace name>.svc.cluster.local (FQDN)

If you are using ambassador to any other API gateway for a service located in another namespace it's always suggested to use short fqdn but it's also fine to use full however make sure it's not auto appending .svc.cluster.local :

            Use : <service name>
            Use : <service.name>.<namespace name>
            Not : <service.name>.<namespace name>.svc.cluster.local

For example, servicename.namespacename.svc.cluster.local,

Description

This will send a request to a particular service inside the namespace you have mentioned.

Extra :

External name service Ref

If you are using the External name as service to resolve the name internally you can use the below for ref

kind: Service
apiVersion: v1
metadata:
  name: service
spec:
  type: ExternalName
  externalName: <servicename>.<namespace>.svc.cluster.local

Here, replace the <servicename> and <namespace> with the appropriate values.

In Kubernetes, namespaces are used to create virtual environment but all are connected with each other through specific DNS convention.

Interrogate answered 12/4, 2019 at 10:58 Comment(8)
Could you explain how this answer is any different from Paul's provided almost 2 years earlier?Moonset
@Moonset there is no difference but i have just specified what to replace service name and namespace at which particular place. while he has used namespace-a so looks confusing to me.Interrogate
A handy trick on SO is to add a comment on the answer and make the necessary clarification.Moonset
I would call this as the best solution because .svc.cluster.local is by default supported for resolving the service internally.Rusell
I don't understand what your first code block is saying. It seems to say that you shouldn't use the fully qualified <service.name>.<namespace.name>.svc.cluster.local but should use <service.name> or <service.name>.<namespace.name> instead? But then goes on to say that you should use the fully qualified one?Mozzarella
it will work both ways FQDN or short FQDN. however i read somewhere using short fqdn also in ambassador api gateway.Interrogate
DNS for Services and PodsMoccasin
Mentioning in the first block one is NOT supposed to use the FDQN but then proceeding in the following examples with that exact FDQN is confusing.Diazine
T
24

To access services in two different namespaces you can use url like this:

HTTP://<your-service-name>.<namespace-with-that-service>.svc.cluster.local

To list out all your namespaces you can use:

kubectl get namespace

And for service in that namespace you can simply use:

kubectl get services -n <namespace-name>

this will help you.

Typewritten answered 23/9, 2020 at 14:39 Comment(0)
C
2

Access services across multiple namespaces using headless services

Actually i found that headless service can be accessed from multiple namespaces without much a do. If you want to go the headless service way then convert your service as follow:

apiVersion: v1
kind: Service
metadata:
  name: nfs-server-svc
  namespace: nfs-server
spec:
  clusterIP: None
  ports:
  - name: nfs
    port: 2049
    targetPort: nfs
    protocol: TCP
  - name: rpcbind
    port: 111
    targetPort: rpcbind
  - name: mountd
    port: 20048
    targetPort: mountd
  selector:
    app: nfs-server-app
  type: ClusterIP

Now you can ssh into any container in any namespace and ping <service.name>.<namespace> or <service.name>.<namespace>.svc or <service.name>.<namespace>.svc.cluster.local. They all resolve. Example:

kubectl -n nfs-server exec -it my-web-deployment-68976cb578-f9v8t -- bash
bash-5.1# ping nfs-server-svc-svc.nfs-server.svc.cluster.local
PING uoe-api-v6-nfs-svc.uoe-api-v6.svc (10.244.2.176): 56 data bytes
64 bytes from 10.244.2.176: seq=0 ttl=62 time=0.877 ms
64 bytes from 10.244.2.176: seq=1 ttl=62 time=0.983 ms
64 bytes from 10.244.2.176: seq=2 ttl=62 time=0.956 ms
^C
--- nfs-server-svc-svc.nfs-server.svc.cluster.local ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.877/0.938/0.983 ms
bash-5.1#

nfs-server-svc-svc.nfs-server.svc.cluster.local

NB: Am using flannel networking plugin with default settings with k8s version v1.24.4 and make sure your container has ping installed.

Cadaver answered 18/9, 2022 at 22:11 Comment(0)
P
1

None of the previous solutions worked for me on OpenShift 4(.11) with default network settings.

I tried this in a route with this: https://docs.openshift.com/container-platform/4.11/networking/routes/route-configuration.html#nw-route-admission-policy_route-configuration enabled, without success. I can reach podA in NS-A from pod B in NS-B with curl but not from a service or a route.

I eventually found a solution by using an EndPointSlice: https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/

In there, the label pointing to the service is the service one can refer to in a route (it does not have to exist, it seems to be usable by the labelname). It looks something like:

apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
  name: slice-it
  namespace: namespace-a
  labels:
    kubernetes.io/service-name: test-service
addressType: FQDN
ports:
  - name: 'http'
    appProtocol: http
    protocol: TCP
    port: 8080
  - name: 'http1'
    appProtocol: http
    protocol: TCP
    port: 8081
endpoints:
  - addresses:
      - "servicename-in-b.namespace_b.svc"
    conditions:
      ready: true

This gives you the option to create a route in namespace A that points to the service in namespace B by using the servicename test-service (in namespace A).

I hope this helps, there may be better ways but this worked for me, to my understanding that is what the ExternalName servicetype should do, but it did not work at all for me with either name notation, internal or external.

Note there are two ports defined because the services I used ran on a different port, this seems to put that together. Improvements and explanation are welcomed.

Pourparler answered 14/3, 2023 at 22:30 Comment(2)
did you created a service also with name test-service?Kincaid
yes, as you can see in the snippet, the test-service is in namespace-a and needs to be there.Pourparler
A
0

You can achieve this by deploying something at a higher layer than namespaced Services, like the service loadbalancer https://github.com/kubernetes/contrib/tree/master/service-loadbalancer. If you want to restrict it to a single namespace, use "--namespace=ns" argument (it defaults to all namespaces: https://github.com/kubernetes/contrib/blob/master/service-loadbalancer/service_loadbalancer.go#L715). This works well for L7, but is a little messy for L4.

Apocopate answered 3/8, 2016 at 18:39 Comment(2)
This project is deprecated now (aug 2018)Elielia
@Prashanth B : Could you update your answer accordingly!Dodds
C
-1

After spending some time trying to implement this in EKS, I have found the solution that might be useful for someone else in the future.

As EKS doesnt support External names, the solution is to create ingresses in each namespace where you have services, and make all ingresses use the same loadbalancer by adding the annotation to each Ingress for IngressGroups, like this:

alb.ingress.kubernetes.io/group.name: my-group

For more details go to this link and search for: To share an application load balancer across multiple Ingress resources using IngressGroups

Click answered 23/12, 2021 at 14:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.