k3s trae por defecto un balanceador propio llamado ServiceLB (antes Klipper) que asigna IPs a los servicios de tipo LoadBalancer usando el rango de IPs del host. Funciona, pero solo dentro del propio nodo. En cuanto necesitas que un servicio sea accesible desde otros equipos de la red con una IP “real” del DHCP, MetalLB es la solución estándar.
Paso 1: Desactivar el balanceador por defecto de k3s
Lo primero es apagar el balanceador que viene de serie, porque no pueden coexistir los dos en el mismo nodo.
-
Abre el archivo de unidad de systemd del servicio k3s:
sudo nano /etc/systemd/system/k3s.service -
Busca la línea que empieza con
ExecStarty añade--disable servicelbal final:ExecStart=/usr/local/bin/k3s server --disable servicelb -
Recarga systemd y reinicia k3s:
sudo systemctl daemon-reload sudo systemctl restart k3s
Tras el reinicio, los servicios de tipo LoadBalancer que ya tuvieras desplegados se quedarán en estado Pending hasta que MetalLB les asigne IP. Es normal.
Paso 2: (Opcional) Modo estricto de ARP
MetalLB en modo Layer 2 (el más común y el que usaremos aquí) funciona mejor cuando Kubernetes tiene activado el modo estricto de ARP en kube-proxy. Con la configuración por defecto de k3s no suele ser necesario tocar nada, y el manifiesto oficial de MetalLB ya configura esto por ti. Lo menciono para que sepas que existe, pero en una instalación estándar puedes saltarte este paso.
Paso 3: Instalar MetalLB mediante manifiestos oficiales
Aplica el manifiesto nativo de MetalLB. Esta es la versión actual en el momento de escribir esta guía; conviene consultar la página de releases por si hay una más nueva:
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/refs/tags/v0.15.3/config/manifests/metallb-native.yaml
Espera un par de minutos y comprueba que los pods estén en Running:
kubectl get pods -n metallb-system
Si ves los pods controller, speaker y webhook-service en estado Running, MetalLB está listo para configurar.
Paso 4: Definir el pool de IPs y el anuncio L2
Ahora viene la parte importante: decirle a MetalLB qué rango de IPs de tu red puede usar para los servicios LoadBalancer. Esas IPs no pueden estar en el rango DHCP de tu router ni asignadas a otros dispositivos, porque MetalLB las gestiona por su cuenta.
Crea un archivo metallb-config.yaml con este contenido:
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: pool-name
namespace: metallb-system
spec:
addresses:
- 192.168.20.200-192.168.20.220
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: adv-name
namespace: metallb-system
spec:
ipAddressPools:
- pool-name
Sustituye el rango 192.168.20.200-192.168.20.220 por uno libre de tu segmento. Yo suelo reservar un tramo de 20 IPs contiguas fuera del DHCP, suficiente para la mayoría de clústeres pequeños.
Aplica la configuración:
kubectl apply -f metallb-config.yaml
Paso 5: Comprobar que Traefik recibe una IP
k3s trae Traefik preinstalado como Ingress Controller. En cuanto MetalLB se activa, Traefik detecta que hay un balanceador real disponible y le pide una IP del pool.
Comprueba qué IP ha tomado:
kubectl get svc -n kube-system traefik
Deberías ver algo así en la columna EXTERNAL-IP:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
traefik LoadBalancer 10.43.120.32 192.168.20.200 80:30443/TCP,443:30444/TCP 5m
Si la EXTERNAL-IP está dentro del rango que configuraste en el pool, MetalLB está funcionando. A partir de aquí, cualquier servicio de tipo LoadBalancer que crees obtendrá una IP del pool automáticamente, y será reachable desde tu LAN.