在你的 Raspberry Pi 家庭实验室上使用 MetalLB 安装 Kubernetes 负载均衡器

将来自你家庭网络的真实 IP 地址分配给你集群中运行的服务,并从你网络中的其他主机访问它们。
117 位读者喜欢这篇文章。
Science lab with beakers

Kubernetes 被设计为与主要云提供商的负载均衡器集成,以提供公共 IP 地址并将流量直接引入集群。一些专业的网络设备制造商也提供控制器,将其物理负载均衡产品集成到私有数据中心的 Kubernetes 安装中。然而,对于在家中运行 Kubernetes 集群的爱好者来说,这两种解决方案都不是很有帮助。

Kubernetes 没有内置的网络负载均衡器实现。裸金属集群,例如安装在 Raspberry Pi 上用于私有云家庭实验室的 Kubernetes 集群,或者实际上任何部署在公共云之外且缺乏昂贵专业硬件的集群,都需要另一种解决方案。MetalLB满足了这一需求,无论是对于爱好者还是大规模部署。

MetalLB 是一个网络负载均衡器,可以将集群服务暴露在网络上的专用 IP 地址上,允许外部客户端连接到 Kubernetes 集群内部的服务。它通过使用第 2 层(数据链路层)使用地址解析协议 (ARP) 或使用第 4 层(传输层)使用边界网关协议 (BGP) 来实现这一点。

虽然 Kubernetes 有一个叫做 Ingress 的东西,它允许 HTTP 和 HTTPS 流量暴露在集群外部,但它支持 HTTP 或 HTTPS 流量,而 MetalLB 可以支持任何网络流量。然而,这更像是一个苹果与橙子的比较,因为 MetalLB 提供未分配 IP 地址到特定集群节点的解析,并将该 IP 分配给 Service,而 Ingress 使用特定的 IP 地址,并根据路由规则在内部将 HTTP 或 HTTPS 流量路由到 Service 或 Services。

MetalLB 只需几个步骤即可设置,在私有家庭实验室集群中尤其有效,并且在 Kubernetes 集群中,它的行为与公共云负载均衡器集成相同。这对于教育目的(即,学习技术如何工作)非常有用,并且使在本地环境和云环境之间“迁移”工作负载变得更容易。

ARP vs. BGP

如前所述,MetalLB 通过 ARP 或 BGP 来解析 IP 地址到特定的主机。用简单的话来说,这意味着当客户端尝试连接到特定的 IP 时,它会询问“哪个主机拥有这个 IP?”并且响应会将它指向正确的主机(即,主机的 MAC 地址)。

使用 ARP,请求会广播到整个网络,并且知道哪个 MAC 地址拥有该 IP 地址的主机响应请求;在这种情况下,MetalLB 的答案将客户端定向到正确的节点。

使用 BGP,每个“对等体”维护一个路由信息表,将客户端定向到处理特定 IP 的主机,以及对等体知道的主机,并将此信息通告给其对等体。当配置为 BGP 时,MetalLB 将集群中的每个节点与网络的路由器对等连接,允许路由器将客户端定向到正确的主机。

在这两种情况下,一旦流量到达主机,Kubernetes 就会接管将流量定向到正确的 Pod。

对于以下练习,你将使用 ARP。消费级路由器不(至少不容易)支持 BGP,即使是支持 BGP 的更高端的消费级或专业路由器也可能难以设置。ARP,尤其是在小型家庭网络中,可能同样有用,并且无需在网络上进行任何配置即可工作。它更容易实现。

安装 MetalLB

安装 MetalLB 非常简单。从 MetalLB 的 GitHub 仓库 下载或复制两个 manifest,并将它们应用到 Kubernetes。这两个 manifest 创建了 MetalLB 组件将要部署到的命名空间以及组件本身:MetalLB 控制器、一个“speaker” daemonset 和服务帐户。

安装组件

一旦你创建了组件,就会生成一个随机密钥,以允许 speaker 之间进行加密通信(即,使服务可访问的协议的“speaker”组件)。

(注意:这些步骤在 MetalLB 的网站上也有。)

包含所需 MetalLB 组件的两个 manifest 是

它们可以下载并使用 kubectl apply 命令应用到 Kubernetes 集群,可以本地应用,也可以直接从 Web 应用

# Verify the contents of the files, then download and pipe then to kubectl with curl
# (output omitted)
$ kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.3/manifests/namespace.yaml
$ kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.3/manifests/metallb.yaml

应用 manifest 后,为 speaker 创建一个随机 Kubernetes 密钥,用于加密通信

# Create a secret for encrypted speaker communications
$ kubectl create secret generic -n metallb-system memberlist --from-literal=secretkey="$(openssl rand -base64 128)"

完成上述步骤将创建并启动所有 MetalLB 组件,但在配置之前它们不会执行任何操作。要配置 MetalLB,请创建一个 configMap,其中描述负载均衡器将使用的 IP 地址池。

配置地址池

MetalLB 需要最后一点设置:一个 configMap,其中包含它可以分配给 Kubernetes Service LoadBalancers 的地址的详细信息。但是,这里有一个小小的注意事项。正在使用的地址不需要绑定到网络中的特定主机,但它们必须是空闲的,供 MetalLB 使用,并且不能分配给其他主机。

在我的家庭网络中,IP 地址由我的路由器运行的 DHCP 服务器分配。此 DHCP 服务器不得尝试分配 MetalLB 使用的地址。大多数消费级路由器允许你决定子网的大小,并且可以配置为仅将该子网中的一部分 IP 分配给主机。

对于 MetalDB,你可以将地址列表指定为一个范围

192.168.2.128-192.168.2.254

你可以选择使用 CIDR 表示法。例如,在我的网络中,我使用子网 192.168.2.1/24,我决定将一半的 IP 地址提供给 MetalLB。子网的前半部分包含从 192.168.2.1192.168.2.126 的 IP 地址。此范围可以用 /25 子网表示:192.168.2.1/25。子网的后半部分也可以用 /25 子网表示:192.168.2.128/25。每个半部分包含 126 个 IP 地址——对于主机和 Kubernetes 服务来说绰绰有余。确保确定适合你自己的网络的子网,并相应地配置你的路由器和 MetalLB。

在配置路由器忽略 192.168.2.128/25 子网(或你正在使用的任何子网)中的地址后,创建一个 configMap,告诉 MetalLB 使用该地址池

# Create the config map
$ cat <<EOF | kubectl create -f -
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: address-pool-1
      protocol: layer2
      addresses:
      - 192.168.2.128/25
EOF

一旦 configMap 被创建,MetalLB 就处于活动状态。是时候试用一下了!

测试 MetalLB

你可以通过创建一个示例 Web 服务来测试新的 MetalLB 配置,你可以使用本系列之前文章中的一个:Kube Verify。使用相同的镜像来测试 MetalLB 是否按预期工作:quay.io/clcollins/kube-verify:01。此镜像包含一个 Nginx 服务器,监听端口 8080 上的请求。你可以查看用于创建该镜像的 Containerfile。如果你愿意,你可以从 Containerfile 构建你自己的容器镜像,并将其用于测试。

如果你之前在 Raspberry Pi 上创建了 Kubernetes 集群,你可能已经运行了 Kube Verify 服务,并且可以跳到关于创建 LoadBalancer 类型服务的部分

如果你需要创建一个 kube-verify 命名空间

如果你还没有 kube-verify 命名空间,请使用 kubectl 命令创建一个

# Create a new namespace
$ kubectl create namespace kube-verify
# List the namespaces
$ kubectl get namespaces
NAME              STATUS   AGE
default           Active   63m
kube-node-lease   Active   63m
kube-public       Active   63m
kube-system       Active   63m
metallb-system    Active   21m
kube-verify       Active   19s

创建命名空间后,在该命名空间中创建一个 deployment

# Create a new deployment
$ cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kube-verify
  namespace: kube-verify
  labels:
    app: kube-verify
spec:
  replicas: 3
  selector:
    matchLabels:
      app: kube-verify
  template:
    metadata:
      labels:
        app: kube-verify
    spec:
      containers:
      - name: nginx
        image: quay.io/clcollins/kube-verify:01
        ports:
        - containerPort: 8080
EOF
deployment.apps/kube-verify created

创建一个 LoadBalancer 类型的 Kubernetes 服务

现在通过创建一个 LoadBalancer 类型的 Kubernetes 服务来暴露 deployment。如果你已经有一个名为 kube-verify 的服务,这将替换该服务

# Create a LoadBalancer service for the kube-verify deployment
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
  name: kube-verify
  namespace: kube-verify
spec:
  selector:
    app: kube-verify
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  type: LoadBalancer
EOF

你可以使用 kubectl expose 命令完成相同的事情

kubectl expose deployment kube-verify -n kube-verify --type=LoadBalancer --target-port=8080 --port=80

MetalLB 正在监听 LoadBalancer 类型的服务,并立即分配一个外部 IP(从你设置 MetalLB 时选择的范围中选择的 IP)。使用 kubectl get service 命令查看新服务和 MetalLB 分配给它的外部 IP 地址

# View the new kube-verify service
$ kubectl get service kube-verify -n kube-verify
NAME          TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)        AGE
kube-verify   LoadBalancer   10.105.28.147   192.168.2.129   80:31491/TCP   4m14s

# Look at the details of the kube-verify service
$ kubectl describe service kube-verify -n kube-verify
Name:                     kube-verify
Namespace:                kube-verify
Labels:                   app=kube-verify
Annotations:              <none>
Selector:                 app=kube-verify
Type:                     LoadBalancer
IP:                       10.105.28.147
LoadBalancer Ingress:     192.168.2.129
Port:                     <unset>  80/TCP
TargetPort:               8080/TCP
NodePort:                 <unset>  31491/TCP
Endpoints:                10.244.1.50:8080,10.244.1.51:8080,10.244.2.36:8080
Session Affinity:         None
External Traffic Policy:  Cluster
Events:
  Type    Reason        Age    From                Message
  ----    ------        ----   ----                -------
  Normal  IPAllocated   5m55s  metallb-controller  Assigned IP "192.168.2.129"
  Normal  nodeAssigned  5m55s  metallb-speaker     announcing from node "gooseberry"

kubectl describe 命令的输出中,注意底部的事件,其中 MetalLB 已分配了一个 IP 地址(你的地址会有所不同),并且正在从你的集群中的一个节点“通告”该分配(同样,你的节点会有所不同)。它还描述了端口、你可以从外部访问服务的外部端口 (80)、容器内部的目标端口(端口 8080)以及流量将通过其路由的节点端口 (31491)。最终结果是,从你的家庭网络中的任何位置,都可以通过负载均衡的 IP 地址在端口 80 上访问在 kube-verify 服务的 Pod 中运行的 Nginx 服务器。

例如,在我的网络上,该服务暴露在 http://192.168.2.129:80 上,我可以从我同一网络上的笔记本电脑 curl 该 IP 地址

# Verify that you receive a response from Nginx on the load-balanced IP
$ curl 192.168.2.129
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <title>Test Page for the HTTP Server on Fedora</title>
(further output omitted)

MetalLB FTW

MetalLB 是家庭 Kubernetes 集群的绝佳负载均衡器。它允许你将来自你家庭网络的真实 IP 地址分配给你集群中运行的服务,并从你家庭网络中的其他主机访问它们。这些服务甚至可以通过你的家庭路由器进行端口转发来暴露在网络之外(但请对此保持谨慎!)。MetalLB 轻松地在家用裸金属计算机、基于 Raspberry Pi 的集群甚至虚拟机上复制类似云提供商的行为,使其易于将工作负载“迁移”到云端,或者只是让你自己熟悉它们的工作方式。最重要的是,MetalLB 简单方便,使访问集群中运行的服务变得轻而易举。

你是否使用过 MetalLB,或者你是否使用其他负载均衡器解决方案?你主要使用 Nginx 或 HAProxy Ingress 吗?请在评论中告诉我!

接下来阅读什么
Chris Collins
Chris Collins 是 Red Hat 的 SRE 和 OpenSource.com 的通讯员,对自动化、容器编排及其周围的生态系统充满热情,并且喜欢在家中为了乐趣而重现企业级技术。

5 条评论

不错

这很棒,我主要使用 traeffik ingress 来暴露服务。
我肯定会在家尝试这个来替换我的 proxmox 设置

使用 IPv6 设置这个,一切都可以直接相互通信,而无需所有额外的 NAT。使用负载均衡器和端口转发将服务暴露给传统的互联网。

嗨 Chris,
一篇关于 Metal-LB 的非常好的文章。
我已经尝试过了,但我被卡住了,无法从我的笔记本电脑访问 LB IP。从 Raspberry Pi 集群访问没有任何问题,但在我家网络中的其他设备上无法工作。

输出
从我的笔记本电脑
vinay@pramukha:~$ curl 192.168.15.216
curl: (7) Failed to connect to 192.168.15.216 port 80: No route to host
vinay@pramukha:~$ curl 192.168.15.214
curl: (7) Failed to connect to 192.168.15.214 port 80: No route to host
vinay@pramukha:~$

从 Pi 集群 Master
ubuntu@k8s-pi-master:~$ curl 192.168.15.216

Test Page for the HTTP Server on Fedora
***************************截断输出******************************

ubuntu@k8s-pi-master:~$ curl 192.168.15.214

.centered
{
text-align:center;
margin-top:0px;
margin-bottom:0px;
padding:0px;
}

Container hostname: microbot-65bc8bdd7c-n4cgl

ubuntu@k8s-pi-master:~$

我知道这有点旧了,但以防其他人有这个问题或类似问题,在仔细检查你的路由器配置后,尝试重启你的路由器... 我已经更改了我的子网掩码,以允许将新的 /24 分配给 metalLB,当我按照 https://metallb.universe.tf/configuration/troubleshooting/ 操作时,我甚至可以看到 ARP ping 发送到正确的主机,但在我重启路由器后,网页才开始工作。不确定这是否正常,或者我只是有一个糟糕的路由器。

回复 作者 Vinay Umesh (未验证)

© . All rights reserved.