Appearance
MetalLB Load Balancing
MetalLB provides LoadBalancer services for bare-metal Kubernetes. It assigns external IPs to services and announces them via Layer 2 (ARP/NDP).
IP Address Pools
Two pools are configured, both with autoAssign: false - IPs must be explicitly requested.
Allocation: The university (ZIM) has allocated us 36 public IPv4 addresses in the 141.89.58.x range and a /64 IPv6 block. Currently 14 IPv4 addresses are in use, leaving 22 available for new services.
External Pool (ips-external.yaml):
| Range | Type |
|---|---|
| 141.89.58.175/32 | IPv4 |
| 141.89.58.180/30 | IPv4 |
| 141.89.58.184/29 | IPv4 |
| 141.89.58.192/28 | IPv4 |
| 141.89.58.208/31 | IPv4 |
| 141.89.58.211/32 | IPv4 |
| 141.89.58.212/30 | IPv4 |
| 2001:638:807:3a::/64 | IPv6 |
Office Pool (ips-office.yaml):
| Range | Type |
|---|---|
| 10.1.0.0/16 | IPv4 |
| 2001:638:807:403::/64 | IPv6 |
L2 Advertisements
Each pool is advertised on a specific network interface:
| Pool | Interface | Nodes |
|---|---|---|
| external | eno2 | cwn1, cwn2, cwn3, cwn4 |
| office | eno3 | cwn1, cwn2, cwn3, cwn4 |
This separates external traffic from internal office network traffic at the physical layer.
Assigning IPs to Services
The cluster uses dual-stack networking - all services get both IPv4 and IPv6 addresses. Since autoAssign: false, every LoadBalancer service must explicitly request IPs using the metallb.io/loadBalancerIPs annotation:
yaml
apiVersion: v1
kind: Service
metadata:
name: my-service
annotations:
metallb.io/loadBalancerIPs: 141.89.58.184,2001:638:807:3a:dd55:81e:44c2:7296
spec:
type: LoadBalancer
ipFamilyPolicy: RequireDualStack
ipFamilies:
- IPv4
- IPv6
ports:
- port: 443
targetPort: 8443
selector:
app: my-appGateway API Integration
Most HTTP/HTTPS services use Kubernetes Gateway API with Istio instead of raw LoadBalancer services. The Gateway resource gets the MetalLB annotation:
yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: my-gateway
annotations:
metallb.io/loadBalancerIPs: 141.89.58.194,2001:638:807:3a:ab20:c4f2:a109:a875
spec:
gatewayClassName: istio
listeners:
- name: https
port: 443
protocol: HTTPS
# ...Istio creates a LoadBalancer service for the Gateway, which inherits the annotation.
Current IP Assignments
| Service | IPs | Purpose |
|---|---|---|
| studi.astaup.de | 141.89.58.175 | Student mailing lists |
| remote-pc | 141.89.58.184 | RDP gateway |
| smtpout | 141.89.58.186 | Outgoing mail |
| lists.astaup.de | 141.89.58.187 | Mailing lists |
| smtpin | 141.89.58.192 | Incoming mail |
| preview.astaup.de | 141.89.58.193 | Webspace (astaup) |
| support.astaup.de | 141.89.58.194 | Zammad tickets |
| user-ingress | 141.89.58.195 | IMAP/SMTP submission |
| idp.astaup.de | 141.89.58.203 | Keycloak/LDAP |
| registry.k8s.astaup.de | 141.89.58.208 | OCI registry |
| brandstuve | 141.89.58.209 | Webspace |
| speakup | 141.89.58.211 | Webspace |
| stupa | 141.89.58.214 | Webspace |
| vefa | 141.89.58.215 | Webspace |
| dns (office) | 10.1.0.254 | Office DNS |
Metaleg Integration
For outbound traffic that needs to use a MetalLB IP as the source address (e.g., SMTP), see Metaleg.
Inspecting MetalLB
Check assigned IPs:
bash
kubectl get svc -A -o wide | grep LoadBalancerCheck IP pool usage:
bash
kubectl get ipaddresspools -n metallb-systemCheck L2 advertisements:
bash
kubectl get l2advertisements -n metallb-systemConfiguration
MetalLB configuration is defined in:
clusters/main/infrastructure/essentials/metallb.yaml- Helm releaseclusters/main/infrastructure/essentials/metallb/ips-external.yaml- External IP poolclusters/main/infrastructure/essentials/metallb/ips-office.yaml- Office IP pool