在Kubernetes中保留SourceIP地址并分配负载



在一个多节点集群中,我们想公开一个处理UDP流量的服务。有两个要求:

  1. 我们希望服务由多个pod(可能在不同节点上运行)备份,以便水平扩展。
  2. 服务需要客户端的UDP源IP地址(即应该使用DNAT而不是SNAT)

这可能吗?

我们目前使用NodePort服务和externalTrafficPolicy: local服务。这将强制DNAT,但只有在被请求节点上运行的pod才会接收流量。似乎没有办法将负载分散到多个mnode上的多个pod上。

我已经看过这个Kubernetes教程和这篇文章了。

问题

我觉得在面对实际问题之前有必要做一些解释,以便理解为什么事情不像预期的那样工作:

通常使用NodePort时,会在集群中的每个节点上暴露一个端口。当呼叫node1:port时,流量将(与ClusterIP类型相同)被转发到与selector匹配的一个Pod,无论该Pod在node1或另一个节点上。

现在是棘手的部分。当使用externalTrafficPolicy: Local时,到达没有Pod的节点上的包将被丢弃。也许下面的插图能更容易理解地解释这种行为。

NodePort与默认externalTrafficPolicy: Cluster:

package --> node1 --> forwards to random pod on any node (node1 OR node2 OR ... nodeX)
NodePortwithexternalTrafficPolicy: Local:
package --> node1 --> forwards to pod on node1 (if pod exists on node1)
package --> node1 --> drops package (if there is no pod on node1)
所以在使用externalTrafficPolicy: Local时,为了能够正确地分配负载,需要解决两个主要问题:
  1. 必须有一个Pod在每个节点上运行,以便包不被丢弃
  2. 客户端必须向多个节点发送包,以便分配负载

解决方案

第一个问题可以通过使用DaemonSet很容易地解决。它将确保在集群中的每个节点上运行一个Pod实例。

也可以使用简单的Deployment,手动管理replicas,并通过使用podAntiAffinity确保节点之间的适当分布。这种方法需要更多的努力来维护,因为replicas必须手动调整,但如果您希望在每个节点上拥有不止一个Pod,则可能很有用。

现在来看第二个问题。最简单的解决方案是让客户端自己实现逻辑,并以轮询原则向所有节点发送请求,然而,这不是一个非常实际和/或现实的方法。

通常当使用NodePort时,它前面仍然有某种负载均衡器来分配负载(这里不考虑Kubernetes服务类型LoadBalancer)。这似乎是多余的,因为默认情况下NodePort将在所有pod上分发流量,然而,被请求的节点仍然获得流量,然后发生另一个跳。此外,如果始终只有同一个节点被寻址,那么一旦该节点宕机(无论出于何种原因),流量将永远无法到达任何pod。因此,出于这些原因(以及许多其他原因),负载均衡器应该始终与NodePort结合使用。要解决这个问题,只需将负载均衡器配置为保留原始客户端的源IP。

此外,根据您运行的云,您有可能能够配置服务类型LoadBalancer而不是NodePort(基本上是NodePort服务+前面的负载均衡器,如上所述),用externalTrafficPolicy: Local配置它并解决前面描述的第一个问题,您实现了想要做的事情。

相关内容

  • 没有找到相关文章

最新更新