Time to see MetalLB in action: deploy an application, expose it via a LoadBalancer Service, verify the external IP, and test access from outside the cluster. This episode also covers basic troubleshooting for unassigned IPs and missing advertisements.

After five episodes of theory and configuration, the most satisfying moment has finally arrived: creating your first LoadBalancer Service that genuinely gets an external IP from MetalLB. In episode 7 you'll deploy an application, expose it via a LoadBalancer Service, verify the assigned IP, and test access from outside the cluster.
Just as important, this episode teaches basic troubleshooting. Problems like an unassigned IP, a missing advertisement, or IP conflicts are the three things that confuse beginners the most. After this episode, you'll have the right diagnostic mindset.
Start with a simple application. We'll use Nginx as an example, then expose it via a LoadBalancer Service:
kubectl create deployment nginx --image=nginx:alpine
kubectl expose deployment nginx --type=LoadBalancer --port=80 --target-port=80kubectl expose deployment nginx --type=LoadBalancer --port=80 creates a LoadBalancer Service using port 80. The MetalLB controller will watch this Service and allocate an IP from the pool — of course, only if the Layer 2 pool from episode 3 is still active.
For those who prefer manifests, the YAML form looks like this:
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
type: LoadBalancer
selector:
app: nginx
ports:
- port: 80
targetPort: 80No matter which way you choose, the result is the same: a Service with spec.type: LoadBalancer ready to receive an external IP.
Wait a few seconds, then check whether the controller has allocated an IP:
kubectl get svc nginx
kubectl get svc nginx -o jsonpath='{.status.loadBalancer.ingress[0].ip}'The kubectl get svc nginx output should show an EXTERNAL-IP column containing 192.168.1.200 (or the first IP of your pool), no longer <pending>. The second jsonpath command reads the IP directly from the Service status.
To see the process in detail, read the events:
kubectl describe svc nginxIn the Events section, you'll see a message like Allocated IP 192.168.1.200 from the MetalLB component. This confirms the controller is working as intended.
Now test from a machine outside the cluster that's on the same network. If you're using Layer 2 mode, that machine must be on the same subnet as the MetalLB IP:
curl http://192.168.1.200
ping -c 3 192.168.1.200curl http://192.168.1.200 should return the default Nginx page, and ping -c 3 192.168.1.200 will be answered by the leader node. If both succeed, your first LoadBalancer Service officially works.
To make sure traffic really flows through the external IP, look at the pod logs:
kubectl logs -l app=nginx --tail=20The logs will record incoming requests along with the client source IP. This is also the starting point for understanding the externalTrafficPolicy differences we'll discuss in episode 9.
If EXTERNAL-IP is still <pending> after a few seconds, the most common causes are:
IPAddressPool hasn't been created or is misspelled.Check in the following order:
kubectl get ipaddresspool
kubectl get svc -A
kubectl get events --field-selector involvedObject.name=nginxkubectl get events --field-selector involvedObject.name=nginx will show error messages from the controller, such as Failed to allocate IP along with the reason.
If the IP is assigned but isn't reachable from outside, the advertisement is probably inactive. Check the advertisement resources and the speaker logs:
kubectl get l2advertisement
kubectl get bgpadvertisement
kubectl logs -n metallb-system -l component=speaker --tail=50kubectl get l2advertisement should show an advertisement referencing your IP pool. If it doesn't, the Service is announced over nothing. The speaker logs show whether the announcement succeeded or there's a network error.
If external access is inconsistent, the IP may be colliding with another device on the network. The telltale symptom: sometimes it reaches your application, sometimes another device. The fix: choose a genuinely free IP block (remember episode 0), or enable avoidBuggyIPs to avoid problematic addresses.
Warning
Never test with an IP that's still in use by DHCP. The confusing "sometimes works, sometimes doesn't" symptom usually comes from exactly this kind of ARP conflict.
Episode 7 gives you your first measurable win: the application is running, the Service got an external IP from the pool, and it's reachable from outside the cluster. You also now have a diagnosis pattern for the three most common problems early in your MetalLB usage.
Key takeaways:
kubectl expose deployment nginx --type=LoadBalancer creates a LoadBalancer Service in one step.EXTERNAL-IP and can be checked with kubectl get svc nginx.curl against the external IP.<pending> means the controller failed to allocate — check the pool, capacity, and events.L2Advertisement or BGPAdvertisement.In the next episode, episode 8, we'll discuss advertisement customization — the interfaces and nodeSelectors options on L2Advertisement, plus communities, aggregationLength, and localPref on BGPAdvertisement, complete with how to use multiple advertisements for different needs.