在 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 分配给服务,而 Ingress 使用特定的 IP 地址并在内部根据路由规则将 HTTP 或 HTTPS 流量路由到服务或多个服务。

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

ARP 与 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 存储库下载或复制两个清单文件,并将它们应用到 Kubernetes。这两个清单文件创建了 MetalLB 组件将要部署到的命名空间以及组件本身:MetalLB 控制器、一个“speaker”守护程序集和服务帐户。

安装组件

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

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

包含所需 MetalLB 组件的两个清单文件是

它们可以下载并使用 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

应用清单文件后,创建一个随机 Kubernetes 密钥供 speaker 用于加密通信

# 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

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

# 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 服务来暴露部署。如果您已经有一个名为 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) 无法连接到 192.168.15.216 端口 80:没有到主机的路由
vinay@pramukha:~$ curl 192.168.15.214
curl: (7) 无法连接到 192.168.15.214 端口 80:没有到主机的路由
vinay@pramukha:~$

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

Fedora 上 HTTP 服务器的测试页
***************************输出已截断******************************

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

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

容器主机名:microbot-65bc8bdd7c-n4cgl

ubuntu@k8s-pi-master:~$

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

回复 作者 Vinay Umesh (未验证)

Creative Commons License本作品根据 Creative Commons Attribution-Share Alike 4.0 International License 许可。
© . All rights reserved.