Kubernetes 上微服务之间集群间通信的最佳方式?

Posted

技术标签:

【中文标题】Kubernetes 上微服务之间集群间通信的最佳方式?【英文标题】:Best way for inter-cluster communication between microservices on Kubernetes? 【发布时间】:2020-07-21 10:07:36 【问题描述】:

我是微服务新手,想了解在 Kubernetes 上部署的微服务中实现以下行为的最佳方式是什么:

有 2 个不同的 K8s 集群。微服务 B 部署在两个集群上。

现在如果微服务 A 调用微服务 B 并且 B 的 pod 在集群 1 中不可用,那么调用应该转到集群 2 的 B。

我可以想象通过使用 Netflix OSS 来实现这个功能,但我在这里没有使用它。

另外,暂时搁置集群间通信,微服务之间应该如何通信?

我知道的一种方法是为每个微服务创建 NodePort 类型的 Kubernetes 服务,并在调用微服务中使用 IP 和 nodePort。

问题:如果有人删除了目标微服务的K8s Service怎么办?在重新创建 K8s 服务时,K8s 将随机分配一个新的 nodePort,然后我将不得不再次返回调用微服务并更改目标微服务的 nodePort。如何与 nodePort 解耦?

我研究了 kubedns,但似乎它只能在集群中工作。

我对 Istio 和 Kubernetes Ingress 的了解非常有限。这些是否提供了我正在寻找的东西?

抱歉,问题太长了。任何形式的指导都会非常有帮助。

【问题讨论】:

有什么理由有人不加评论就对这个问题投了反对票? 为什么不设置一个虚拟网络并允许某些子域使用端点 IP 地址相互通信。例如,在 Azure 世界中,为每个 kubernates 集群创建 vnet 和 vnet 网关,然后在它们之间创建一个连接。我们已经在 GCP 和 Azure 上做到了这一点。工作得很好。 【参考方案1】:

您的设计非常接近 Istio Multicluster 示例。

按照Istio multicluster lab 中的步骤,您将获得两个集群和一个 Istio 控制平面,用于平衡位于两个独立 Kubernetes 集群中的两个 ClusterIP 服务之间的流量。

实验室的configuration 监视流量负载,但是重写 Controller Pod 代码,您可以将其配置为在 Cluster One 的 Service 没有端点时将流量切换到 Second Cluster(某种类型的所有 Pod 都未就绪状态)。

这只是一个例子,你可以改变istiowatcher.gocode来实现你想要的任何逻辑。


more advanced solution 使用 Admiral 作为 Istio 多集群管理自动化工具。

Admiral 为跨多个集群的 Istio 网格提供自动配置,以基于将在多个集群上运行的工作负载与服务相关联的唯一服务标识符作为单个网格工作。它还提供跨集群的 Istio 配置的自动配置和同步。这减轻了开发人员和网格操作员的负担,有助于扩展到几个集群之外。

此解决方案解决了现代 Kubernetes 基础架构的这些关键要求:

创建与命名空间分离的服务 DNS 条目,如多网格部署的特性中所述。 跨多个集群的服务发现。 支持主动-主动和 HA/DR 部署。我们还必须通过跨离散集群将服务部署在全球唯一的命名空间中来支持这些关键的弹性模式。

这个解决方案可能会变得非常有用。

【讨论】:

感谢您的回答。您能否与@KoopaKiller 进行下面的讨论?它对我到底想要什么有更多的见解。感谢您的帮助! 我已经阅读了您所有的 cmets,如果您花一些时间完成所有步骤,我相信该实验室几乎可以回答您的所有问题。在前提条件下执行此操作可能会更复杂一些,但我确信 GCP 免费层足以完成实验。【参考方案2】:

您可以使用服务公开您的应用程序,您可以使用某些类型的服务:

ClusterIP:在集群内部 IP 上公开服务。选择此值使服务只能从集群内访问。这是默认的ServiceType

NodePort:在静态端口(@98​​7654332@)上公开每个节点 IP 上的服务。自动创建ClusterIP 服务,NodePort 服务路由到该服务。您可以通过请求<NodeIP>:<NodePort>,从集群外部联系NodePort 服务。

LoadBalancer:使用云提供商的负载均衡器在外部公开服务。自动创建外部负载均衡器路由到的NodePortClusterIP 服务。

ExternalName:通过返回CNAME 记录将服务映射到externalName 字段的内容(例如foo.bar.example.com

对于内部通信,您可以使用服务类型ClusterIP,您可以为您的应用程序配置服务 dns,而不是 IP。 即:可以使用 dns http://my-app-1 或 fqdn http://my-app-1.<namespace>.svc.cluster.local 在内部访问名为 my-app-1 的服务。

对外交流,可以使用NodePortLoadBalancer

NodePort 当你有几个节点并且知道所有节点的 ip 时很好。是的,通过service docs 你可以指定一个特定的端口号:

如果您需要特定的端口号,可以在nodePort 字段中指定一个值。控制平面将为您分配该端口或报告 API 事务失败。这意味着您需要自己处理可能的端口冲突。您还必须使用有效的端口号,该端口号在为 NodePort 配置的使用范围内。

LoadBalancer给你更多的灵活性,因为你不需要知道所有节点的ip,你只需要知道服务IP和端口。但是LoadBalancer只支持cloudproviders,如果你想在裸机集群中实现,我建议你看看MetalLB。

Finnaly,还有另一个选项是使用ingress,在我看来是向外部公开 HTTP 应用程序的最佳方式,因为您可以通过路径和主机创建规则,它比服务更灵活.但支持 HTTP/HTTPS,如果需要 TCP 则转到服务

我建议您查看此链接,以深入了解服务和入口的工作原理:

Kubernetes Services

Kubernetes Ingress

nginx Ingress

【讨论】:

非常感谢您抽出时间来回答。我当然不能使用 LoadBalancer 类型的服务,因为我有没有任何云提供商的裸机 Kubernetes 集群。我不想使用 NodePort 类型,因为如果 cluster1 上的 mS1 与 cluster2 上的 mS2 对话,并且如果 mS2 的服务被删除或 nodePort 以任何方式更改,那么我将不得不在 mS1 的配置中更改 mS2 的 nodePort,这很痛苦.我想与 nodePort 解耦。 ClusterIP 对我没有用处,因为我想要集群间服务通信。 我正在使用 Istio,结果发现它只使用了原生 K8s 的服务发现机制。我尝试使用 Eureka 和 Ribbon 进行服务发现,但结果发现 Kubernetes pod 的名称是在 Eureka 而不是 Kubernetes 服务中注册的。所以 Ribbon 不理解 pod 的名称。我现在正在探索 Consul,但似乎它的行为就像 Eureka 一样。我应该编写自己的服务发现机制吗?我可以创建一个 Service Registry 微服务,它将注册所有微服务,然后使用自定义客户端进行 URL 解析。 裸机集群可以使用LoadBalancer类型,只需要安装MetalLB。使用 MetalLB,您可以从您的网络配置一个 IP 范围,并且服务将获取此 IP 并可以从您的网络访问。如果这些解决方案中的任何一个对您来说都不可行,您可以编写自己的服务发现。有机会尝试 MetalLB,也许它可以帮助并节省编写自定义服务发现的时间。 我确实探索了 Metallb,当我第一次看到它时,我如释重负。但当我浏览它的文档时,我发现:“大部分代码更改,以及项目的总体方向,都是一个人的个人努力,在业余时间在动机允许的情况下从事 MetalLB。这个这意味着,目前,支持和新功能开发主要取决于一个人的可用性和资源。你应该适当地设定你的期望。所以我显然不能在我的生产系统中使用 Metallb。 我正在考虑试用 Consul 和 Linkerd。看看这些可以提供什么。【参考方案3】:

使用 ingress 进行集群间通信,使用集群 ip 类型的服务进行两个微服务之间的集群内通信。

【讨论】:

感谢您的回复。您能否浏览一下我在上面回复 KoopaKiller 时发布的 cmets?

以上是关于Kubernetes 上微服务之间集群间通信的最佳方式?的主要内容,如果未能解决你的问题,请参考以下文章

kubernetes 集群中 cilium 的实践及其网络通信解析

Kubernetes:我应该使用 HTTPS 在服务之间进行通信吗

防止 Kubernetes 中的命名空间间通信

Kubernetes集群中微服务之间如何进行JWT认证

Kubernetes — 网络流量模型

[K8s]Kubernetes-服务负载均衡联网(上)