Part 2 of 2 — Replacing NodePort with real LoadBalancer IPs, routing traffic through an Ingress controller with clean hostnames, and locking down pod-to-pod communication with NetworkPolicy. All on bare metal. All verified with real tests. Series navigation: Part 1: Cluster setup with kubeadm, foundational workloads, deploying a full-stack app with ConfigMaps, Secrets, StatefulSets, and CI pipelines → Read Part 1 Part 2 (you are here): MetalLB, Nginx Ingress Controller, clean hostnames, and NetworkPolicy enforcement with real tests Full source code: All Kubernetes manifests referenced in this article are available at github.com/otie16/k8s-homelab-vm-project If you followed Part 1, you have a working two-node Kubernetes cluster running a full-stack application — Next.js frontend, Django REST API, and PostgreSQL. You can reach it at 192.168.1.100:30001 and 192.168.1.100:30000 . That works. But it's not how production Kubernetes is meant to work.…