ITPub博客

首页 > 数据库 > 数据库开发技术 > Kubernetes LoadBalancer Service 与负载均衡器

Kubernetes LoadBalancer Service 与负载均衡器

原创 数据库开发技术 作者:云原生指北 时间:2022-09-30 16:15:00 0 删除 编辑

之前介绍过一些 Ingress 使用,比如 Ingress SSL 透传、Ingress 的多租户。从 Demo 看起来是创建 Ingress 之后,就能从集群外访问服务了。实际上除了 Ingress 的作用以外,还有 Kubernetes Service 和负载均衡器(Load Balancer)参与(当 Service 类型为 LoadBalancer 时)。

这篇文章就来介绍了 Kubernetes LoadBalancer Service 和两个比较典型的负载均衡器的工作原理。

LoadBalancer Service

Service 是 Kubernetes 中的资源类型,用来将一组 Pod 的应用作为网络服务公开。每个 Pod 都有自己的 IP,但是这个 IP 的生命周期与 Pod 生命周期一致,也就是说 Pod 销毁后这个 IP 也就无效了(也可能被分配给其他的 Pod 使用)。而 Service 的 IP(ClusterIP) 则是在创建之后便不会改变,Service 与 Pod 之前通过 userspace 代理、iptables 和 ipvs 代理 等手段关联。

LoadBalancer 是 Service 四种类型中的一种,其他三种是 ClusterIP、NodePort、ExternalName。

LoadBalancer 的工作需要搭配第三方的负载均衡器来完成。当我们安装 Ingress 控制器时,会创建一个类型为 LoadBalancer 的 Service。新创建的 Service 的 EXTERNAL-IP 状态是 pending,假如没有负载均衡器的话,会一直处于 pending 状态:

NAME                          TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
fsm-ingress-pipy-controller   LoadBalancer   10.43.188.208   <pending>     80:30508/TCP   8s

在 Demo 中用的是 K3s(默认提供了负载均衡器),这个 Service 会获得 EXTERNAL-IP,192.168.1.12和 192.168.1.13 是集群中两个节点的 IP,当我们使用该 IP 地址访问时,流量会进入到 Ingress 控制器的 pod,然后路由到配置对应的 pod 中。

NAME                          TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S) 
fsm-ingress-pipy-controller   LoadBalancer   10.43.188.208   192.168.1.12,192.168.1.13   80:30508/TCP   47s

如何实现的呢?

K3s 服务端的 controller 运行时会监听集群中 Service 的变更,如果 Service 类型是 LoadBalancer 便为其创建一个 Daemonset ,传入 Service 的 ClusterIP、Protocol、Port 等信息。剩下的工作就由这个 Daemonset 来完成了。

而这个 Daemonset 使用的是 klipper-lb 的镜像。

Klipper LB

klipper-lb 是 K3s 的一个开源负载均衡器的实现,实现很简单:使用主机端口(pod.spec.containers.ports.hostPort 与 Service 的端口号相同)来接收流量,并使用 iptables 将接收的流量转发到 Service的 ClusterIP。

Pod 启动时使用通过环境变量注入的 Service 的信息,创建 iptables 的 NAT 规则。

代码量很少:

#!/bin/sh
set -e -x

trap exit TERM INT

for dest_ip in ${DEST_IPS}
do
    if echo ${dest_ip} | grep -Eq ":" 
    then
        if [ `cat /proc/sys/net/ipv6/conf/all/forwarding` != 1 ]; then
            exit 1
        fi
        ip6tables -t nat -I PREROUTING ! -s ${dest_ip}/128 -p ${DEST_PROTO} --dport ${SRC_PORT} -j DNAT --to [${dest_ip}]:${DEST_PORT}
        ip6tables -t nat -I POSTROUTING -d ${dest_ip}/128 -p ${DEST_PROTO} -j MASQUERADE
    else
        if [ `cat /proc/sys/net/ipv4/ip_forward` != 1 ]; then
            exit 1
        fi
        iptables -t nat -I PREROUTING ! -s ${dest_ip}/32 -p ${DEST_PROTO} --dport ${SRC_PORT} -j DNAT --to ${dest_ip}:${DEST_PORT}
        iptables -t nat -I POSTROUTING -d ${dest_ip}/32 -p ${DEST_PROTO} -j MASQUERADE
    fi
done

if [ ! -e /pause ]; then
    mkfifo /pause
fi
</pause

那除了 klipper-lb 以外,今天介绍下另一种负载均衡器 metallb。

Metal LB

MetalLB 是裸机 Kubernetes 集群的负载均衡器实现,使用标准路由协议。

注意: MetalLB 目前还是 beta 阶段。

  • 在 Kubernetes 集群中使用 MetalLB 作为 LoadBalancer(上)- Layer2
  • 在 Kubernetes 集群中使用 MetalLB 作为 LoadBalancer(下)- BGP

关于 Metal LB,在上面的文章介绍过。其有两种工作模式,这里通过 BGP 的工作模式来进行说明。

与 klipper-lb 不同的时,我们需要预先配置好可用的 IP 地址段。当创建 LoadBalancer 类型的 Service时,metallb 会从地址池中为其分配 IP 地址。

以 Daemonset 方式运行在各个节点的 speaker 组件会监听 Service 的变更,如果该 Service 已经分配了 IP 地址(service.status.loadBalancer.ingress),speaker 在完成一些列的校验工作后会向路由器声明该地址。

路由接收到 speaker 的广播后,会更新路由表:使用 speaker 的节点进行该 IP 的路由。

当请求该 IP 地址时,因为无法找到 IP 地址对应的 MAC 地址(没有 ARP 广播),便将请求转给路由器。路由器根据路由表中的记录进行路由,转发到对应的节点上。后续的流程,就是 iptables/kubeproxy 的工作了。

可能你也看出来,如果目标 pod 不在该节点上 ,还会再有一次转发。这种情况可以通过设置 Service 的 externalTrafficPolicy 来避免。

如果 service.sepc.externalTrafficPolicy 设置为 Local,只有 Service 的 Endpoints 所在的节点,才会参与广播和路由;否则,所有的节点都会参与广播和路由。

总结

由于篇幅的原因,本文只介绍了两种不同负载均衡器的工作原理,没有深入探索其实现细节。不同云提供商的负载均衡器的实现可能各不相同,不同实现间也各有优缺点。


原文作者:云原生指北;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2020-03-04

  • 博文量
    130
  • 访问量
    54632