25 MetalLB en K3s (con el modo de capa 2) #
MetalLB es una implementación de equilibrador de carga para clústeres de Kubernetes en bare metal que utiliza protocolos de enrutamiento estándar.
En esta guía se explica cómo desplegar MetalLB en el modo de capa 2 (L2).
25.1 Por qué usar este método #
MetalLB es una opción conveniente para el equilibrio de carga en clústeres bare metal de Kubernetes por varias razones:
Integración nativa con Kubernetes: MetalLB se integra a la perfección con Kubernetes, lo que facilita el despliegue y la gestión mediante las herramientas y prácticas habituales de Kubernetes.
Compatibilidad bare metal: a diferencia de los equilibradores de carga basados en la nube, MetalLB se ha diseñado específicamente para despliegues locales en las que los sistemas de equilibrio de carga tradicionales podrían no estar disponibles o no ser viables.
Compatibilidad con múltiples protocolos: MetalLB admite el modo de capa 2 y BGP (Border Gateway Protocol, protocolo de gateway de frontera), lo que proporciona flexibilidad para diferentes arquitecturas y requisitos de red.
Alta disponibilidad: dado que distribuye el equilibrio de carga entre varios nodos, MetalLB garantiza una alta disponibilidad y fiabilidad para sus servicios.
Escalabilidad: MetalLB puede manejar despliegues a gran escala, y se va adaptando con su clúster de Kubernetes para satisfacer la demanda creciente.
En el modo de capa 2 (L2), un nodo asume la responsabilidad de anunciar un servicio a la red local. Desde la perspectiva de la red, simplemente parece que esa máquina tiene varias direcciones IP asignadas a su interfaz de red.
La mayor ventaja del modo de capa 2 es su universalidad: funciona en cualquier red Ethernet sin necesidad de hardware especial, ni siquiera de routers sofisticados.
25.2 MetalLB en K3s (con L2) #
En este inicio rápido, se utilizará el modo L2. Esto significa que no se necesita equipo de red especial, solo tres IP libres dentro del rango de red.
25.3 Requisitos previos #
Un clúster K3s donde se vaya a desplegar MetalLB.
K3S incluye su propio equilibrador de carga de servicios llamado
Klipper. Debe
inhabilitarlo para ejecutar MetalLB. Para inhabilitar Klipper, hay
que instalar K3s mediante el indicador
--disable=servicelb
.
Helm
Tres direcciones IP libres dentro del rango de red. En este ejemplo
192.168.122.10-192.168.122.12
Debe asegurarse de que esas direcciones IP no están asignadas. En un entorno DHCP esas direcciones no deben formar parte del pool DHCP para evitar dobles asignaciones.
25.4 Despliegue #
Utilizaremos el chart de Helm de MetalLB publicado como parte de la solución SUSE Edge:
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 Configuración #
En este punto, la instalación ya está completa. Ahora hay que configurarla con nuestros valores de ejemplo:
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
Ahora, está lista para usarse. Es posible personalizar muchas cosas en el modo L2, por ejemplo:
Y mucho más para BGP.
25.5.1 Traefik y MetalLB #
Traefik se despliega por defecto con K3s (se puede
inhabilitar con --disable=traefik
) y se expone por
defecto como LoadBalancer
(para usarse con Klipper). Sin
embargo, como hay que inhabilitar Klipper, el servicio Traefik para Ingress
sigue siendo de tipo LoadBalancer
. Por lo tanto, en el
momento de desplegar MetalLB, la primera IP se asignará automáticamente para
Traefik Ingress.
# 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
Esto se aplicará más tarde en el proceso (Sección 25.6.1, “Ingress con MetalLB”).
25.6 Uso #
Vamos a crear un despliegue de ejemplo:
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
Y, por último, el servicio:
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
Veámoslo en acción:
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 Ingress con MetalLB #
Como Traefik ya sirve como controlador de Ingress, podemos exponer todo el
tráfico HTTP/HTTPS a través de un objeto Ingress
como:
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
Y, a continuación:
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>
Verifique que MetalLB funciona correctamente:
% 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
En el ejemplo anterior, el flujo de tráfico es el siguiente:
hellok3s.${IP}.sslip.io
se resuelve en la IP real.Después, el tráfico se gestiona con el pod
metallb-speaker
.metallb-speaker
redirige el tráfico al controladortraefik
.Por último, Traefik reenvía la petición al servicio
hello-kubernetes
.