介绍

Kubernetes Services 是将运行在一组 Pod 上的应用程序公开为网络服务的抽象方法。这一组 Pod 能够被 Service 访问到,通常是通过 Labels 和 Selectors 实现的。 当客户端连接到 Kubernetes Service 时,连接会被负载均衡到支持服务的其中一个 Pod 上,如这个概念下图所示。

Kubernetes Services 主要有三种类型:

  • Cluster IP
  • Node Port
  • Load Balancer

Cluster IP services

默认 Service 类型是 ClusterIP。这允许通过虚拟 IP 地址在群集内访问服务。服务的 Cluster IP 可通过 Kubernetes 域名系统发现。例如,在 Service 的生命周期内,域名和 Cluster IP 地址保持不变,即使支持 Service 的 Pod 可能会被创建或销毁,并且支持 Service 的 Pod 的数量可能会随着时间的推移而变化。

在典型的 Kubernetes 部署中,kube-proxy 运行在每个节点上,负责拦截到 Cluster IP 地址的连接,并在支持每个服务的一组 Pod 之间进行负载均衡。作为该过程的一部分,DNAT用于将目的 IP 地址从 Cluster IP 映射到所选的 Pod。然后,连接上的响应数据包在返回到启动连接的 Pod 的过程中会发生 NAT 反向。

重要的是,网络策略是基于 Pod 而不是服务 Cluster IP 来执行的。(即在DNAT将连接的目的IP变更为所选服务 Pod 后,对客户端 Pod 执行的是出口网络策略。而由于只改变了连接的目的IP,所以 Pod 的入口网络策略将原客户端 Pod 视为连接的源头)。)

Node port services

从集群外部访问服务的最基本方式是使用 NodePort 类型的服务。节点端口是群集中每个节点上保留的端口,通过它可以访问服务。在典型的 Kubernetes 部署中,kube-proxy 负责拦截到节点端口的连接,并在支持每个服务的 Pod 之间对它们进行负载均衡。

作为这个过程的一部分,NAT 用于将目标 IP 地址和端口从节点 IP 和节点 Port 映射到所选择的后面 Pod 和 Service Port。另外源 IP 地址从客户端 IP 映射到 Node IP,这样连接上的响应数据包就会通过原来的节点流回来,NAT 可以反过来。(执行 NAT 的节点才有逆转 NAT 所需的连接跟踪状态)。

请注意,由于连接源 IP 地址被 SNAT 化为 Node IP 地址,服务后面 Pod 的入口网络策略不会看到原始客户端 IP 地址。通常情况下,这意味着任何此类策略都仅限于限制目标协议和端口,而不能基于客户端/源IP进行限制。在某些场景下,可以通过使用外部 TrafficPolicy 或使用 Calico 的 eBPF 数据平面原生服务处理(而不是 kube-proxy)来规避这种限制,后者保留了源 IP 地址。

Load balancer services

LoadBalancer 类型的服务通过外部网络负载均衡器 (NLB) 暴露服务。网络负载均衡器的确切类型取决于哪个公有云提供商,或者如果是 on-prem,则取决于与您的集群集成的特定硬件负载均衡器集成。

可以通过网络负载均衡器上的特定 IP 地址从集群外部访问该服务,默认情况下,网络负载均衡器会使用服务节点端口在各节点间进行负载均衡。

大多数网络负载平衡器会保留客户端的源 IP 地址,但由于服务随后会通过节点端口进行,因此 Pod 本身看不到客户端的 IP 地址,这对网络策略也有同样的影响。与节点端口一样,在某些情况下,可以通过使用 externalTrafficPolicy 或使用 Calico 的 eBPF 数据平面本地服务处理(而不是 kube-proxy)来避免这种限制,后者保留了源 IP 地址。

Advertising service IPs

使用节点端口或网络负载均衡器的一种替代方法是通过 BGP 发布服务 IP 地址广播。 这需要集群运行在支持 BGP 的底层网络上,这通常意味着使用标准 Top of Rack 路由器进行内部部署。

Calico 支持广播服务群集 IP,或为配置有群集 IP 的服务发布外部 IP。如果你没有使用 Calico 作为网络插件,那么 MetalLB 提供了类似的功能,可以与各种不同的网络插件配合使用。

externalTrafficPolicy:local

默认情况下,无论是使用服务类型 NodePort 或 LoadBalancer,还是通过 BGP 公布服务 IP 地址,从群集外部访问服务都会在支持该服务的所有 Pod 上均匀地进行负载均衡,而与 Pod 所在的节点无关。这种行为可以通过使用 externalTrafficPolicy:local 配置服务来更改,该策略指定连接只应负载均衡到本地节点上支持该服务的 Pod。

当与 LoadBalancer 类型的服务或与 Calico 服务 IP 地址广播相结合时,流量仅被定向到至少有一个 Pod 支持服务的节点。这减少了节点之间潜在的额外网络跳转,也许更重要的是,要保持源 IP 地址一直到 Pod,因此网络策略可以根据需要限制特定的外部客户。

需要注意的是,在服务类型为 LoadBalancer 的情况下,并非所有的负载均衡器都支持这种模式。而在服务 IP 广播的情况下,负载均衡的均匀性变得依赖于拓扑结构。在这种情况下,可以使用 Pod 反亲和规则来确保备份 Pod 在拓扑中的均匀分布,但这确实为部署服务增加了一些复杂性。

Calico eBPF native service handling

作为使用 Kubernetes 标准 kube-proxy 的替代方案,Calico 的 eBPF 数据平面支持本地服务处理。这保留了源 IP 以简化网络策略,提供了 DSR (直接服务器返回)以减少返回流量的网络跳数,并提供了独立于拓扑的负载均衡,与 kube-proxy 相比,减少了 CPU 使用和延迟。