'Service located in another namespace
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:
- Define a
serviceX
service innamespaceA
, without a selector (since the POD I want to select isn't innamespaceA
). - Define a service (which I also called
serviceX
) innamespaceB
, and then - Define an Endpoints object in
namespaceA
to point toserviceX
innamespaceB
.
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.
Solution 1:[1]
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
Solution 2:[2]
It is so simple to do it.
If you want to use it as host and want to resolve it,
If you are using ambassador to any other API gateway for service located in another namespace it's always suggested to use :
Use : <service name>
Use : <service.name>.<namespace name>
Not : <service.name>.<namespace name>.svc.cluster.local
for example, servicename.namespacename.svc.cluster.local
this will send request to a particular service inside the namespace you have mentioned.
service example:
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.
Solution 3:[3]
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.
Solution 4:[4]
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.
Solution 5:[5]
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
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Jay Modi |
Solution 3 | dswiecki |
Solution 4 | Prashanth B |
Solution 5 | Ivan |