MetalLB¶
MetalLB provides LoadBalancer services for bare-metal Kubernetes clusters, enabling external access to services in local development environments.
Overview¶
MetalLB is deployed in local Kind clusters to provide LoadBalancer functionality that would normally be provided by cloud load balancers.
Configuration¶
Deployment Location¶
- Configuration:
apps/infra/metallb/ - Environment: Local development only
- Chart: Official MetalLB Helm chart
Values Structure¶
Address Pool Configuration¶
Local Development Pool¶
Configuration: apps/infra/metallb/local/extra/cluster1.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: default
namespace: metallb-system
spec:
addresses:
- 172.18.255.200-172.18.255.250
autoAssign: true
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: default
namespace: metallb-system
spec:
ipAddressPools:
- default
Address Range Planning¶
Kind Network Range: 172.18.0.0/16
- Cluster nodes: 172.18.0.2-172.18.0.10
- Pod CIDR: 10.244.0.0/16
- Service CIDR: 10.96.0.0/12
- MetalLB pool: 172.18.255.200-172.18.255.250
Layer 2 Configuration¶
L2 Advertisement¶
Why Layer 2 Mode? - Simpler configuration for local development - No BGP router requirements - Direct ARP/NDP responses - Suitable for single-node or small clusters
Configuration:
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: default
namespace: metallb-system
spec:
ipAddressPools:
- default
nodeSelectors:
- matchLabels:
node-role.kubernetes.io/control-plane: ""
Service Integration¶
LoadBalancer Services¶
Example Service Configuration:
apiVersion: v1
kind: Service
metadata:
name: nginx-service
namespace: default
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: nginx
loadBalancerIP: 172.18.255.200 # Optional: specific IP
Ingress Controller Integration¶
NGINX Ingress with MetalLB:
apiVersion: v1
kind: Service
metadata:
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
type: LoadBalancer
ports:
- name: http
port: 80
targetPort: http
- name: https
port: 443
targetPort: https
selector:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/component: controller
Advanced Configuration¶
Multiple Address Pools¶
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: web-services
namespace: metallb-system
spec:
addresses:
- 172.18.255.200-172.18.255.220
autoAssign: false
---
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: api-services
namespace: metallb-system
spec:
addresses:
- 172.18.255.221-172.18.255.240
autoAssign: false
Service Selector¶
Target Specific Pools:
apiVersion: v1
kind: Service
metadata:
name: web-service
annotations:
metallb.universe.tf/address-pool: web-services
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 8080
selector:
app: web-app
BGP Configuration (Optional)¶
BGP Mode Setup¶
For more advanced networking:
apiVersion: metallb.io/v1beta2
kind: BGPPeer
metadata:
name: router-peer
namespace: metallb-system
spec:
myASN: 64512
peerASN: 64512
peerAddress: 172.18.0.1
sourceAddress: 172.18.0.2
---
apiVersion: metallb.io/v1beta1
kind: BGPAdvertisement
metadata:
name: default
namespace: metallb-system
spec:
ipAddressPools:
- default
Monitoring and Troubleshooting¶
Status Checking¶
# Check MetalLB pods
kubectl get pods -n metallb-system
# Check IP address pools
kubectl get ipaddresspool -n metallb-system
# Check L2 advertisements
kubectl get l2advertisement -n metallb-system
# Check service external IPs
kubectl get svc --all-namespaces -o wide
Service Status¶
# Check LoadBalancer services
kubectl get svc -o wide | grep LoadBalancer
# Describe service for events
kubectl describe svc <service-name> -n <namespace>
# Check service endpoints
kubectl get endpoints <service-name> -n <namespace>
Common Issues¶
External IP Pending: 1. Check MetalLB controller status 2. Verify IP address pool configuration 3. Check L2Advertisement setup 4. Review network connectivity
IP Assignment Conflicts: 1. Check address pool ranges 2. Verify no external DHCP conflicts 3. Review existing IP assignments 4. Check network bridge configuration
Logs and Events¶
# MetalLB controller logs
kubectl logs -n metallb-system deployment/controller
# MetalLB speaker logs
kubectl logs -n metallb-system daemonset/speaker
# System events
kubectl get events --sort-by=.metadata.creationTimestamp
Network Testing¶
Connectivity Tests¶
# Test external IP access
curl http://172.18.255.200
# Check ARP table
arp -a | grep 172.18.255
# Ping test
ping 172.18.255.200
# Port connectivity
nc -zv 172.18.255.200 80
Docker Network Inspection¶
# Check Kind network
docker network ls | grep kind
# Inspect network details
docker network inspect kind
# Check container IPs
docker ps | grep kind
docker inspect <container-id> | grep IPAddress
Integration with Kind¶
Kind Cluster Configuration¶
Cluster setup with port mapping:
# kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
kubeadmConfigPatches:
- |
kind: InitConfiguration
nodeRegistration:
kubeletExtraArgs:
node-labels: "ingress-ready=true"
extraPortMappings:
- containerPort: 80
hostPort: 80
protocol: TCP
- containerPort: 443
hostPort: 443
protocol: TCP
Network Bridge Setup¶
Docker bridge configuration:
# Check bridge networks
docker network ls
# Create custom bridge (if needed)
docker network create --driver bridge \
--subnet=172.19.0.0/16 \
--ip-range=172.19.240.0/20 \
kind-custom
Security Considerations¶
Network Isolation¶
Namespace restrictions:
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: secure-pool
namespace: metallb-system
spec:
addresses:
- 172.18.255.240-172.18.255.250
namespaces:
- secure-namespace
Access Control¶
Service-specific pools:
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: secure-advertisement
namespace: metallb-system
spec:
ipAddressPools:
- secure-pool
nodeSelectors:
- matchLabels:
security-level: high
Performance Tuning¶
Speaker Configuration¶
apiVersion: v1
kind: ConfigMap
metadata:
name: config
namespace: metallb-system
data:
config: |
address-pools:
- name: default
protocol: layer2
addresses:
- 172.18.255.200-172.18.255.250
bgp-communities:
no-advertise: 65535:65282
Resource Limits¶
controller:
resources:
limits:
cpu: 100m
memory: 100Mi
requests:
cpu: 50m
memory: 50Mi
speaker:
resources:
limits:
cpu: 100m
memory: 100Mi
requests:
cpu: 50m
memory: 50Mi
Best Practices¶
Address Planning¶
- Reserve address ranges for different service types
- Avoid conflicts with existing network infrastructure
- Document IP assignments for troubleshooting
- Use consistent naming for pools and advertisements
Development Workflow¶
- Start with Layer 2 for simplicity
- Test connectivity before deploying applications
- Monitor resource usage of MetalLB components
- Regular cleanup of unused IP assignments
Maintenance¶
- Regular updates of MetalLB charts
- Monitor logs for errors and warnings
- Test failover scenarios in multi-node setups
- Document network topology for team reference
Limitations¶
Layer 2 Mode Limitations¶
- Single node handling traffic per service
- ARP table limitations in large networks
- Network broadcast dependency
- Limited scalability compared to BGP mode
Kind-Specific Limitations¶
- Docker network dependency
- Host network access requirements
- Port mapping conflicts with host services
- Limited multi-cluster networking
Migration from NodePort¶
Service Type Migration¶
Before (NodePort):
apiVersion: v1
kind: Service
metadata:
name: app-service
spec:
type: NodePort
ports:
- port: 80
targetPort: 8080
nodePort: 30080
selector:
app: my-app
After (LoadBalancer with MetalLB):
apiVersion: v1
kind: Service
metadata:
name: app-service
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 8080
selector:
app: my-app
DNS Configuration¶
Update DNS records to point to LoadBalancer IPs instead of NodePort combinations.