25 K3s 上的 MetalLB(使用第 2 层模式) #
MetalLB 是使用标准路由协议的裸机 Kubernetes 群集的负载平衡器实现。
本指南将展示如何以第 2 层 (L2) 模式部署 MetalLB。
25.1 为何使用此方法 #
由于以下原因,MetalLB 成为了用来实现裸机 Kubernetes 群集负载平衡的较佳选择:
与 Kubernetes 本机集成:MetalLB 可无缝与 Kubernetes 集成,让用户可使用熟悉的 Kubernetes 工具和方法轻松进行部署和管理。
裸机兼容性:与基于云的负载平衡器不同,MetalLB 专门用于本地部署,在这种部署中,可能无法使用传统负载平衡器或使用传统负载平衡器不现实。
支持多种协议:MetalLB 支持 Layer 2 和 BGP(边界网关协议)模式,提供了很大的灵活性,适合不同的网络架构并可满足不同的要求。
高可用性:MetalLB 可以将负载平衡负担分散在多个节点中,从而确保服务的高可用性和可靠性。
可伸缩性:MetalLB 可以处理大规模部署,并且能够将 Kubernetes 群集扩容来满足日益增长的需求。
在第 2 层模式下,一个节点负责向本地网络播发服务。从网络的角度看,似乎为该计算机的网络接口分配了多个 IP 地址。
第 2 层模式的主要优势在于其通用性:它可以在任何以太网上正常工作,不需要任何特殊硬件,甚至不需要各种形式的路由器。
25.2 K3s 上的 MetalLB(使用 L2) #
本快速入门将使用 L2 模式。这意味着我们不需要任何特殊网络设备,只需使用网络范围内的三个空闲 IP。
25.3 先决条件 #
要部署 MetalLB 的 K3s 群集。
K3S 自身附带服务负载平衡器(名为 Klipper)。需要禁用 Klipper 才能运行
MetalLB。要禁用 Klipper,需使用 --disable=servicelb
标志安装
K3s。
Helm
网络范围内的三个空闲 IP 地址。在本示例中为
192.168.122.10-192.168.122.12
必须确保这三个 IP 地址未被分配。在 DHCP 环境中,为了避免出现双重分配情况,不得将这些地址添加到 DHCP 池中。
25.4 部署 #
我们将使用作为 SUSE Edge 解决方案一部分发布的 MetalLB Helm chart:
helm install \
metallb oci://registry.suse.com/edge/charts/metallb \
--namespace metallb-system \
--create-namespace
while ! kubectl wait --for condition=ready -n metallb-system $(kubectl get\
pods -n metallb-system -l app.kubernetes.io/component=controller -o name)\
--timeout=10s; do
sleep 2
done
25.5 配置 #
安装现已完成。接下来请使用示例值进行配置:
cat <<-EOF | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: ip-pool
namespace: metallb-system
spec:
addresses:
- 192.168.122.10/32
- 192.168.122.11/32
- 192.168.122.12/32
EOF
cat <<-EOF | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: ip-pool-l2-adv
namespace: metallb-system
spec:
ipAddressPools:
- ip-pool
EOF
现在,MetalLB 可供您使用。可以自定义 L2 模式的许多设置,例如:
还可以对 BGP 进行其他许多自定义设置。
25.5.1 Traefik 和 MetalLB #
默认情况下,Traefik 会随 K3s 一起部署(可以使用 --disable=traefik
禁用
Traefik),并作为 LoadBalancer
公开(与 Klipper
一起使用)。但是,由于需要禁用 Klipper,用于入口的 Traefik 服务仍是 LoadBalancer
类型。因此在部署 MetalLB 的那一刻,第一个 IP 将自动分配给 Traefik 入口。
# Before deploying MetalLB
kubectl get svc -n kube-system traefik
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
traefik LoadBalancer 10.43.44.113 <pending> 80:31093/TCP,443:32095/TCP 28s
# After deploying MetalLB
kubectl get svc -n kube-system traefik
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
traefik LoadBalancer 10.43.44.113 192.168.122.10 80:31093/TCP,443:32095/TCP 3m10s
我们将在稍后的过程(第 25.6.1 节 “MetalLB 的入口”)中应用此操作。
25.6 用法 #
我们来创建示例部署:
cat <<- EOF | kubectl apply -f -
---
apiVersion: v1
kind: Namespace
metadata:
name: hello-kubernetes
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: hello-kubernetes
namespace: hello-kubernetes
labels:
app.kubernetes.io/name: hello-kubernetes
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-kubernetes
namespace: hello-kubernetes
labels:
app.kubernetes.io/name: hello-kubernetes
spec:
replicas: 2
selector:
matchLabels:
app.kubernetes.io/name: hello-kubernetes
template:
metadata:
labels:
app.kubernetes.io/name: hello-kubernetes
spec:
serviceAccountName: hello-kubernetes
containers:
- name: hello-kubernetes
image: "paulbouwer/hello-kubernetes:1.10"
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 8080
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
env:
- name: HANDLER_PATH_PREFIX
value: ""
- name: RENDER_PATH_PREFIX
value: ""
- name: KUBERNETES_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: KUBERNETES_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: KUBERNETES_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: CONTAINER_IMAGE
value: "paulbouwer/hello-kubernetes:1.10"
EOF
最后创建服务:
cat <<- EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
name: hello-kubernetes
namespace: hello-kubernetes
labels:
app.kubernetes.io/name: hello-kubernetes
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
selector:
app.kubernetes.io/name: hello-kubernetes
EOF
我们来看看此示例的实际效果:
kubectl get svc -n hello-kubernetes
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-kubernetes LoadBalancer 10.43.127.75 192.168.122.11 80:31461/TCP 8s
curl http://192.168.122.11
<!DOCTYPE html>
<html>
<head>
<title>Hello Kubernetes!</title>
<link rel="stylesheet" type="text/css" href="/css/main.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Ubuntu:300" >
</head>
<body>
<div class="main">
<img src="/images/kubernetes.png"/>
<div class="content">
<div id="message">
Hello world!
</div>
<div id="info">
<table>
<tr>
<th>namespace:</th>
<td>hello-kubernetes</td>
</tr>
<tr>
<th>pod:</th>
<td>hello-kubernetes-7c8575c848-2c6ps</td>
</tr>
<tr>
<th>node:</th>
<td>allinone (Linux 5.14.21-150400.24.46-default)</td>
</tr>
</table>
</div>
<div id="footer">
paulbouwer/hello-kubernetes:1.10 (linux/amd64)
</div>
</div>
</div>
</body>
</html>
25.6.1 MetalLB 的入口 #
由于 Traefik 已用作入口控制器,我们可以通过 Ingress
对象公开任何 HTTP / HTTPS
流量,例如:
IP=$(kubectl get svc -n kube-system traefik -o jsonpath="{.status.loadBalancer.ingress[0].ip}")
cat <<- EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hello-kubernetes-ingress
namespace: hello-kubernetes
spec:
rules:
- host: hellok3s.${IP}.sslip.io
http:
paths:
- path: "/"
pathType: Prefix
backend:
service:
name: hello-kubernetes
port:
name: http
EOF
然后运行:
curl http://hellok3s.${IP}.sslip.io
<!DOCTYPE html>
<html>
<head>
<title>Hello Kubernetes!</title>
<link rel="stylesheet" type="text/css" href="/css/main.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Ubuntu:300" >
</head>
<body>
<div class="main">
<img src="/images/kubernetes.png"/>
<div class="content">
<div id="message">
Hello world!
</div>
<div id="info">
<table>
<tr>
<th>namespace:</th>
<td>hello-kubernetes</td>
</tr>
<tr>
<th>pod:</th>
<td>hello-kubernetes-7c8575c848-fvqm2</td>
</tr>
<tr>
<th>node:</th>
<td>allinone (Linux 5.14.21-150400.24.46-default)</td>
</tr>
</table>
</div>
<div id="footer">
paulbouwer/hello-kubernetes:1.10 (linux/amd64)
</div>
</div>
</div>
</body>
</html>
校验 MetalLB 是否正常工作:
% arping hellok3s.${IP}.sslip.io
ARPING 192.168.64.210
60 bytes from 92:12:36:00:d3:58 (192.168.64.210): index=0 time=1.169 msec
60 bytes from 92:12:36:00:d3:58 (192.168.64.210): index=1 time=2.992 msec
60 bytes from 92:12:36:00:d3:58 (192.168.64.210): index=2 time=2.884 msec
在以上示例中,流量的流动方式如下:
hellok3s.${IP}.sslip.io
解析为实际 IP。然后,流量由
metallb-speaker
Pod 处理。metallb-speaker
将流量重定向到traefik
控制器。最后,Traefik 将请求转发到
hello-kubernetes
服务。