2026
Kubernetes Service Types: NodePort vs ClusterIP vs LoadBalancer
A practical guide to the three core Service types. What they do, when to use each and how they layer on top of each other.
When you deploy an application in Kubernetes, the Pods that run your workload are ephemeral. They come and go, get rescheduled across nodes and receive new IP addresses each time. A Service is the Kubernetes abstraction that gives you a stable network endpoint to reach those Pods, though not all Services work the same way.
ClusterIPNodePortLoadBalancerELI5
Imagine your Kubernetes cluster is an apartment building. Pods are people living in individual apartments. They move around and their room numbers change. Services are the building's reception desk: a stable address that forwards to the right person.
ClusterIPThe reception desk is inside the building.
Only residents (other Pods) can walk up to it. Guests from outside cannot get in.
NodePortA special side door on every floor.
Anyone who knows the building's address AND the floor number can knock on that door and be connected to the right resident.
LoadBalancerA professional doorman out front.
Guests only need the official building address. The doorman figures out which door and floor to send them to.
ClusterIP
—Internal cluster traffic only.
ClusterIP)The default Service type. Gives your Service a stable virtual IP that only other Pods inside the cluster can reach. kube-proxy on each node maintains iptables rules that DNAT traffic to one of the backing Pods.
apiVersion: v1kind: Servicemetadata: name: my-serviceThe Service name.
spec: type: ClusterIPThe default type, so it can be omitted entirely.
selector: app: my-appMatches Pods with this label.
ports: - port: 80The port the Service exposes inside the cluster.
targetPort: 8080The port the container actually listens on.
NodePort
—External traffic via any node's IP on a static port.
NodePort)Opens a port on every node in the cluster. Any external client that knows a node IP and the port can reach the Service. A NodePort Service always gets a ClusterIP too, it builds on top of it.
Note
The caller must know a node IP (not production-friendly). If the hit node doesn't run a target Pod, kube-proxy adds an extra network hop. Use externalTrafficPolicy: Local to avoid this, but then only nodes with a running Pod accept traffic.
apiVersion: v1kind: Servicemetadata: name: my-servicespec: type: NodePortOpens a port on every node in the cluster.
selector: app: my-app ports: - port: 80 targetPort: 8080 nodePort: 30080Optional. If omitted, Kubernetes auto-assigns a value in the 30000–32767 range.
LoadBalancer
—External traffic via a cloud-provisioned public IP.
LoadBalancer)Provisions a cloud load balancer in front of your cluster. The LB gets a stable public IP and distributes traffic to the NodePort on your nodes. Kubernetes automatically creates a NodePort and ClusterIP underneath.
Tip
In production, use one LoadBalancer Service pointing to an Ingress Controller (nginx-ingress, Traefik) rather than a separate LB per app. One cloud LB instead of many, with significant cost savings.
apiVersion: v1kind: Servicemetadata: name: my-servicespec: type: LoadBalancerProvisions a cloud load balancer automatically.
selector: app: my-app ports: - port: 80Public-facing port on the cloud LB.
targetPort: 8080Container port. Kubernetes handles the NodePort underneath.
How they relate to each other
A key insight: every Service type builds on the previous one. When you create a LoadBalancer Service, Kubernetes also automatically allocates a NodePort and a ClusterIP. The cloud provider's load balancer then forwards traffic to the node ports.
LoadBalancer
└─►NodePort(always created underneath)
└─►ClusterIP(always created underneath)
└─►kube-proxy / iptables rules
Deep dive: traffic flow
ClusterIPPod A
DNS lookup: my-service → 10.96.0.1
kube-proxy
Intercepts via iptables/IPVS, DNAT to a backing Pod IP
Target Pod
Response travels back directly
NodePortExternal client
<node-ip>:30080
kube-proxy
Forwards to the ClusterIP (extra hop if no local Pod)
Target Pod
Standard ClusterIP routing from here
If the chosen node doesn't run a target Pod, kube-proxy forwards to another node, adding an extra network hop. Avoid this with externalTrafficPolicy: Local, but then only nodes with a target Pod accept traffic.
LoadBalancerExternal client
http://203.0.113.10:80
Cloud LB
Distributes across registered node IP + NodePort combos
Kubernetes NodePort
Handles the rest from here
When to use what
ClusterIP- Services only need to talk to each other inside the cluster
- You expose a database, cache, or internal API
- You do not want the service reachable from outside at all
NodePort- Running locally (minikube or kind) without a cloud LB
- Quick external access for testing or demos
- Managing your own external load balancer (HAProxy, nginx) outside Kubernetes
LoadBalancer- Running on a managed cloud (AKS, EKS, GKE, etc.)
- Need a stable public IP with health checks
- Exposing a production service to end users
LoadBalancer without a cloud provider
A common misconception is that type: LoadBalancer only works on public clouds. In reality, it just requires something that watches for LoadBalancer Services and provisions an IP in response. On bare-metal or on-prem clusters, you can install a controller that does exactly that.
Popular on-prem solutions
How MetalLB works
In a cloud environment, the cloud controller manager watches for type: LoadBalancer Services and calls the cloud API to provision a load balancer. On bare-metal there is no cloud API, so the Service stays in Pending state forever, unless you install something like MetalLB.
Configure an IP pool
e.g. 192.168.1.200–192.168.1.250
Service is created
MetalLB assigns an IP from the pool to the LoadBalancer Service.
IP is announced
Via ARP (Layer 2 mode) or to upstream routers via BGP (Layer 3 mode).
Traffic arrives
Reaches a node and follows normal NodePort → ClusterIP routing.
Summary by environment
Cloud controller manager → cloud LB
MetalLB, kube-vip, or similar → virtual IP via ARP/BGP
Cloud provider integration or MetalLB
Quick comparison
Summary
Understanding these three types is essential before diving into more advanced topics like Ingress, Gateway API, or Service Meshes. All of which ultimately rely on these building blocks.