The most common combination on bare-metal clusters: MetalLB exposes the Ingress Controller, and Ingress splits traffic across many Services. This episode covers setting up Nginx Ingress as a LoadBalancer, the comparison with NodePort, and the end-to-end flow from an application to Ingress and out through MetalLB.

Exposing every application with its own LoadBalancer Service is possible, but it wastes IPs and is hard to manage. That's where Ingress comes in: a single entry point that splits traffic across many Services based on hostname or path. The combination of MetalLB and an Ingress Controller is the most common pattern on bare-metal clusters — MetalLB provides the external IP, and Ingress splits the traffic.
Episode 12 guides you through building this pattern with the Nginx Ingress Controller: installing the controller, exposing it via a LoadBalancer Service, comparing it with the NodePort approach, and assembling the end-to-end flow from an application to Ingress and out through MetalLB.
Without Ingress, one application needs one LoadBalancer IP. With Ingress, a single LoadBalancer IP can serve dozens of applications — the router is the Ingress Controller, which evaluates requests based on hostname and path.
kubectl get svc -AIn kubectl get svc -A, you'll see many internal ClusterIP Services and only one LoadBalancer Service for Ingress. That's a significant IP saving, especially for pools with limited capacity.
The traffic flow becomes:
The fastest way to install the Nginx Ingress Controller is via Helm:
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx --namespace ingress-nginx --create-namespacehelm install ingress-nginx ingress-nginx/ingress-nginx --namespace ingress-nginx creates the controller in the ingress-nginx namespace. Wait until the controller pod reports Running:
kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginxBy default, the Nginx Ingress chart creates a Service of type LoadBalancer. MetalLB will allocate an external IP for this Service from the configured pool:
kubectl get svc ingress-nginx-controller -n ingress-nginx
kubectl get svc ingress-nginx-controller -n ingress-nginx -o jsonpath='{.status.loadBalancer.ingress[0].ip}'If EXTERNAL-IP is filled in — for example 192.168.1.201 — MetalLB has successfully exposed the Ingress Controller. kubectl get svc ingress-nginx-controller -n ingress-nginx is the command to check that status.
The Ingress IP must also be announced. In Layer 2 mode, check from another machine that the IP answers ARP. In BGP mode, check the routes on the router. Both checks use the same steps as episodes 5 and 6.
Both approaches can expose Ingress, but there are important differences:
externalTrafficPolicy: Local, and there's no need to remember a random port.http://192.168.1.10:31234.For production, LoadBalancer is by far the cleaner choice. NodePort remains useful as a quick fallback or when IP blocks are limited.
Now let's put it all together. Deploy two applications and create hostname-based Ingress rules:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo-apps
spec:
ingressClassName: nginx
rules:
- host: app1.example.internal
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app1
port:
number: 80
- host: app2.example.internal
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app2
port:
number: 80From a machine outside the cluster, point the hostname at the Ingress LoadBalancer IP:
curl --resolve app1.example.internal:80:192.168.1.201 http://app1.example.internal
curl -H "Host: app1.example.internal" http://192.168.1.201curl -H "Host: app1.example.internal" http://192.168.1.201 forces Nginx to treat the request as if it were for that hostname. If the app1 application answers, the end-to-end flow works: application to Ingress, out through MetalLB.
Episode 12 completes the Ingress + MetalLB pattern: one external IP serves many applications, the Ingress Controller is exposed via a LoadBalancer Service, and the end-to-end flow from application to outside the cluster is proven to work.
Key takeaways:
helm install ingress-nginx ingress-nginx/ingress-nginx is the fastest install path.kubectl get svc ingress-nginx-controller -n ingress-nginx checks the IP allocated by MetalLB.curl -H "Host: ..." to verify Ingress routing.In the next episode, episode 13, we'll discuss peering & network design — multi-peer BGP configuration, using routerID, planning the advertised subnets, placing IP pools, and coordinating with firewalls so peering and advertisement work securely.