Create kubernetes nginx ingress without GCP load-balancer
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
On GKE, the default Ingress path usually provisions a Google Cloud load balancer. If you want NGINX ingress without that managed load balancer, you need to avoid the GCE ingress controller and expose your NGINX ingress controller in another way, typically with NodePort, host networking, or an external solution such as MetalLB in non-GKE environments. The key is that the Kubernetes Ingress object alone does not create reachability; the controller's own Service type does.
Do Not Use the GCE Ingress Controller
If you create an Ingress on GKE without care, the cluster may hand it to the Google controller and provision cloud resources. That is the behavior you are trying to avoid.
Instead, deploy the NGINX ingress controller and make sure your Ingress resources are targeted at it, usually through an ingress class.
This tells Kubernetes which controller should watch the resource.
Expose the NGINX Controller With NodePort
The most common way to avoid a cloud load balancer is to expose the ingress controller as a NodePort Service.
Traffic can then reach any cluster node on those ports. You can front that with your own VM, external reverse proxy, firewall rule, or DNS pointing directly at node IPs.
This avoids the managed GCP load balancer, but it also means you take responsibility for external traffic routing.
Controller Deployment Still Matters
You still need the NGINX ingress controller itself running in the cluster. A minimal Deployment looks like this.
In practice you would normally install the controller with Helm or the official manifest rather than hand-writing every resource, but the structure is the same.
Understand the Tradeoff
Removing the cloud load balancer changes the operational model.
You gain:
- lower dependence on GCP-managed ingress infrastructure
- more control over traffic entry
- the ability to run a similar pattern across environments
You lose:
- managed external IP lifecycle
- automatic L4 load balancing across nodes
- some of the operational simplicity GKE normally provides
That tradeoff is often fine for dev clusters, on-prem-style environments, or setups with an existing external reverse proxy.
Host Networking and DaemonSet Options
Another pattern is running the ingress controller on every node with host ports or host networking. That can work, but it increases scheduling and port-management complexity. For most clusters, NodePort is the cleaner first option when the goal is simply to avoid a cloud load balancer.
DNS and External Reachability Are Your Responsibility
Once the controller is exposed through NodePort, DNS must resolve to something that can actually reach those node ports. That could be:
- node public IPs
- a separate reverse proxy
- a hardware load balancer outside Kubernetes
- a VPN-reachable internal address range
Without that extra layer, the ingress exists inside Kubernetes but remains unreachable from clients.
Common Pitfalls
- Creating an
Ingresson GKE and accidentally letting the GCE controller claim it. - Exposing the ingress controller as
LoadBalancerand then wondering why GCP resources were created. - Forgetting that
Ingressroutes traffic only after the controller itself is reachable. - Skipping
ingressClassNameand relying on controller defaults. - Underestimating the operational work that the managed cloud load balancer had been doing for you.
Summary
- To avoid a GCP load balancer, use the NGINX ingress controller instead of the GCE ingress controller.
- Expose the NGINX controller with
NodePort, host networking, or another non-cloud-LB mechanism. - Set
ingressClassName: nginxso the right controller handles theIngressresource. - The
Ingressobject defines routing, but the controller Service defines reachability. - When you remove the managed load balancer, you take over external traffic delivery yourself.

