MetalLB (layer 2) — noble
Prerequisite (Talos + cni: none): install Cilium (or your CNI) before MetalLB.
Until the CNI is up, nodes stay NotReady and carry taints such as node.kubernetes.io/network-unavailable (and not-ready). The scheduler then reports 0/N nodes are available: N node(s) had untolerated taint(s) and MetalLB stays Pending — its chart does not tolerate those taints, by design. Install Cilium first (talos/CLUSTER-BUILD.md Phase B); when nodes are Ready, reinstall or rollout MetalLB if needed.
Order: namespace (Pod Security) → Helm (CRDs + controller) → kustomize (pool + L2).
If kubectl apply -k fails with no matches for kind "IPAddressPool" / ensure CRDs are installed first, Helm is not installed yet.
Pod Security warnings (would violate PodSecurity "restricted"): MetalLB’s speaker/FRR use hostNetwork, NET_ADMIN, etc. That is expected unless metallb-system is labeled privileged. Apply namespace.yaml before Helm so the namespace is created with the right labels (omit --create-namespace on Helm), or patch an existing namespace:
kubectl apply -f clusters/noble/apps/metallb/namespace.yaml
If you already ran Helm with --create-namespace, either kubectl apply -f namespace.yaml (merges labels) or:
kubectl label namespace metallb-system \
pod-security.kubernetes.io/enforce=privileged \
pod-security.kubernetes.io/audit=privileged \
pod-security.kubernetes.io/warn=privileged --overwrite
Then restart MetalLB pods if they were failing (kubectl get pods -n metallb-system; delete stuck pods or kubectl rollout restart each Deployment / DaemonSet in that namespace).
-
Install the MetalLB chart (CRDs + controller). If you applied
namespace.yamlabove, skip--create-namespace:helm repo add metallb https://metallb.github.io/metallb helm repo update helm upgrade --install metallb metallb/metallb \ --namespace metallb-system \ --wait -
Apply this folder’s pool and L2 advertisement:
kubectl apply -k clusters/noble/apps/metallb -
Confirm a
Servicetype: LoadBalancerreceives an address in192.168.50.210–192.168.50.229(e.g.kubectl get svc -n traefik traefikafter installing Traefik inclusters/noble/apps/traefik/).
Reserve one IP in that range for Argo CD (e.g. 192.168.50.210) via spec.loadBalancerIP or chart values when you expose the server. Traefik pins 192.168.50.211 in clusters/noble/apps/traefik/values.yaml.
Pending MetalLB pods
kubectl get nodes— every nodeReady? IfNotReadyorNetworkUnavailable, finish CNI install first.kubectl describe pod -n metallb-system <pod-name>— read Events at the bottom (0/N nodes are available: …).- L2 speaker uses the node’s uplink; kube-vip in this repo expects
ens18on control planes (clusters/noble/apps/kube-vip/vip-daemonset.yaml). If your NIC name differs, changevip_interfacethere.