【问题标题】:Service located in another namespace位于另一个命名空间中的服务
【发布时间】:2016-09-10 07:52:51
【问题描述】:

我一直在尝试找到一种方法来在一个命名空间中定义一个服务,该服务链接到在另一个命名空间中运行的 Pod。我知道在namespaceA 中运行的 Pod 中的容器可以通过在集群 DNS 中将其引用为serviceX.namespaceB.svc.cluster.local 来访问在namespaceB 中定义的serviceX,但我宁愿没有容器内的代码需要了解serviceX 的位置。也就是说,我希望代码只查找serviceX,然后能够访问它。

Kubernetes documentation 表明这是可能的。它说您定义没有选择器的服务的原因之一是您希望将您的服务指向另一个命名空间或另一个集群中的服务

这表明我应该:

  1. namespaceA 中定义一个serviceX 服务,没有选择器(因为我要选择的POD 不在namespaceA 中)。
  2. namespaceB中定义一个服务(我也叫serviceX),然后
  3. 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 被分配为在namespaceBserviceX 的ClusterIP;namespaceA 中的serviceX192.168.0.0/16 子网上自动分配了不同的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 要解决的问题。

那么,有没有一种方法可以满足文档的承诺,即我可以将一个命名空间中的服务指向在不同命名空间中运行的服务

一位评论者质疑您为什么要这样做 - 这是一个至少对我来说有意义的用例:

假设您有一个多租户系统,其中还包括一个可以在租户之间共享的通用数据访问功能。现在想象一下,这个数据访问函数有不同风格的通用 API,但性能特征不同。一些租户可以访问其中一个,其他租户可以访问另一个。

每个租户的 pod 都在自己的命名空间中运行,但每个人都需要访问这些常见的数据访问服务之一,这些服务必然位于另一个命名空间中(因为它由多个租户访问)。但是,如果租户更改订阅以访问性能更高的服务,您不希望租户必须更改其代码。

一个潜在的解决方案(我能想到的最简洁的解决方案,如果它有效的话)是在每个租户的命名空间中包含一个服务定义,用于数据访问服务,每个服务定义都针对适当的端点进行配置。此服务定义将被配置为指向每个租户有权使用的正确数据访问服务。

【问题讨论】:

  • 命名空间的重点是隔离,所以我认为如果你需要跨越命名空间,你至少需要知道它的位置!
  • 那么,当文档建议您可以通过不定义选择器并暗示定义端点来指示在一个命名空间中定义的服务访问不同命名空间中的服务时,文档意味着什么?这肯定有有效的用例——我在问题中添加了其中一个。文档只是误导,还是有一种我还没有弄清楚的方法?
  • 我不确定,抱歉。我所知道的是我使用他们的 fqdn 访问多个命名空间中的服务。我特别用 vpn 来做这件事,因为我有 1 个 vpn pod,并且我通过它的所有服务进行连接。但是您需要知道命名空间并提供 fqdn。我建议你在 slack 频道上提问。
  • 使用 fqdn 是我目前使用的解决方案。不过,如果没有必要,我的用例会得到更好的服务(现在添加到问题中)。
  • 我也想知道文档指的是什么,但是我可以使用 fqdn 作为我用例的令人满意的解决方案。

标签: kubernetes


【解决方案1】:

您可以通过在比命名空间服务更高的层部署一些东西来实现这一点,例如服务负载平衡器https://github.com/kubernetes/contrib/tree/master/service-loadbalancer。如果要将其限制为单个命名空间,请使用“--namespace=ns”参数(默认为所有命名空间:https://github.com/kubernetes/contrib/blob/master/service-loadbalancer/service_loadbalancer.go#L715)。这适用于 L7,但对于 L4 来说有点混乱。

【讨论】:

  • 此项目现已弃用(2018 年 8 月)
  • @Prashanth B:你能相应地更新你的答案吗!
【解决方案2】:

我偶然发现了同样的问题,并找到了一个不需要任何静态 ip 配置的好解决方案:

您可以通过DNS name 访问服务(正如您所提到的):servicename.namespace.svc.cluster.local

您可以使用该 DNS 名称在 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

【讨论】:

  • 这是一个很好的解决方案!当我最初问这个问题时,我不确定“ExternalName”类型是否可用于服务,但现在支持它,并且巧妙地解决了问题。谢谢,保罗。
  • 这行得通吗?我怀疑。谁能确认这是否真的有效,对我不起作用。
  • 是的。它适用于一个 pod 与另一个命名空间中的服务通信,但不适用于入口负载均衡器。
  • 由于fix kubernetes in-cluster CNAME lookup,旧版本可能无法使用。
  • 这是否也适用于 kube-system 命名空间中的服务?
【解决方案3】:

做起来很简单

如果您想将其用作主机并想解决它

如果您使用大使到任何其他 API 网关以获取位于另一个命名空间中的服务,则始终建议您使用:

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

它会像:servicename.namespacename.svc.cluster.local

这将向您提到的命名空间内的特定服务发送请求。

示例:

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

这里将&lt;servicename&gt;&lt;namespace&gt; 替换为适当的值。

在 Kubernetes 中,命名空间用于创建虚拟环境,但它们都是相互连接的。

【讨论】:

  • 您能解释一下这个答案与保罗近 2 年前提供的答案有何不同吗?
  • @Oliver 没有区别,但我刚刚指定了在哪个特定位置替换服务名称和命名空间的内容。虽然他使用了 namespace-a,但我看起来很困惑。
  • 关于 SO 的一个方便技巧是在答案中添加评论并进行必要的澄清。
  • 我认为这是最好的解决方案,因为 .svc.cluster.local 默认支持内部解析服务。
  • 我不明白你的第一个代码块在说什么。似乎是说您不应该使用完全限定的&lt;service.name&gt;.&lt;namespace.name&gt;.svc.cluster.local,而应该使用&lt;service.name&gt;&lt;service.name&gt;.&lt;namespace.name&gt;?但接着说你应该使用完全限定的?
【解决方案4】:

要访问两个不同命名空间中的服务,您可以像这样使用 url:

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

列出您可以使用的所有命名空间:

kubectl get namespace

对于该命名空间中的服务,您可以简单地使用:

kubectl get services -n <namespace-name>

这会对你有所帮助。

【讨论】:

    【解决方案5】:

    在花了一些时间尝试在 EKS 中实现这一点后,我发现了将来可能对其他人有用的解决方案。

    作为 EKS doesnt support External names,解决方案是在您拥有服务的每个命名空间中创建入口,并通过向 IngressGroups 的每个入口添加注释来使所有入口使用相同的负载均衡器,如下所示:

    alb.ingress.kubernetes.io/group.name: 我的组

    欲了解更多详情,请访问this link 并搜索: 使用 IngressGroup 跨多个 Ingress 资源共享应用程序负载均衡器

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-11
      • 1970-01-01
      • 1970-01-01
      • 2021-08-08
      • 2012-05-27
      • 2018-01-05
      相关资源
      最近更新 更多