问题描述
我一直在尝试找到一种方法来在一个名称空间中定义服务,该服务链接到在另一个名称空间中运行的Pod.我知道在namespaceA
中运行的Pod中的容器可以通过在群集DNS中将其引用为serviceX.namespaceB.svc.cluster.local
来访问namespaceB
中定义的serviceX
,但是我宁愿容器内的代码不需要了解serviceX
的位置.也就是说,我希望代码只查找serviceX
然后可以访问它.
Kubernetes文档认为这是可能的.它说,您要在没有选择器的情况下定义服务的原因之一是您要将服务指向另一个命名空间或另一个群集中的服务.
这表明我应该:
- 在
namespaceA
中定义一个serviceX
服务,没有选择器(因为我要选择的POD不在namespaceA
中). - 在
namespaceB
中定义服务(我也称为serviceX
),然后 - 在
namespaceA
中定义一个Endpoints对象以指向namespaceB
中的serviceX
.
这是我无法完成的第三步.
首先,我尝试通过以下方式定义Endpoints对象:
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
这似乎是合乎逻辑的方法,并且显然 targetRef
的作用是什么.但是,这导致一个错误,指出addresses
数组中的ip
字段是强制性的.因此,我的下一个尝试是为namespaceB
中的serviceX
分配一个固定的ClusterIP地址,并将其放在IP字段中(请注意,将service_cluster_ip_range
配置为192.168.0.0/16
,并且将192.168.1.1
分配为在192.168.0.0/16
子网中为namespaceB
中的serviceX
; namespaceA
中的serviceX
自动分配了另一个ClusterIP):
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
这被接受,但是对namespaceA
中的serviceX
的访问未转发到namespaceB
中的Pod-它们超时.查看iptables设置,看起来它必须要做两次NAT预路由才能完成此操作.
我发现唯一可行的方法-但不是令人满意的解决方案-是在namespaceB
中查找提供serviceX
的Pod的实际IP地址,并将该地址放在namespaceA
中的Endpoints对象中.当然,这并不令人满意,因为Pod IP地址可能会随着时间变化.这就是服务IP需要解决的问题.
因此,有没有一种方法可以满足文档中的承诺,即我可以将一个命名空间中的服务指向在另一个命名空间中运行的 service ?
一个评论者质疑您为什么要这样做-这是一个至少对我来说有意义的用例:
假设您有一个多租户系统,该系统还包括可以在租户之间共享的通用数据访问功能.现在想象一下,具有常见API的此数据访问功能有不同的风格,但性能特征也不同.一些租户可以访问其中一个,其他租户可以访问另一个.
每个租户的Pod在各自的命名空间中运行,但是每个租户的Pod都需要访问这些公共数据访问服务之一,这些服务必定位于另一个命名空间中(因为它被多个租户访问).但是,如果租户的订阅发生更改以访问性能更高的服务,则您不希望租户更改其代码.
一种可能的解决方案(如果能解决的话,我认为是最干净的解决方案)是在数据访问服务的每个租户的命名空间中包括一个服务定义,并为相应的端点配置每个服务.该服务定义将配置为指向每个租户有权使用的适当的数据访问服务.
我偶然发现了同一问题,发现了一个不需要任何静态IP配置的不错的解决方案:
您可以通过 DNS名称访问服务(如您所述): servicename.namespace.svc.cluster.local
您可以使用该DNS名称在另一个通过本地服务命名空间:
kind: Service
apiVersion: v1
metadata:
name: service-y
namespace: namespace-a
spec:
type: ExternalName
externalName: service-x.namespace-b.svc.cluster.local
ports:
- port: 80
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.
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-x.namespace-b.svc.cluster.local
ports:
- port: 80
这篇关于服务位于另一个名称空间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!