
Kubernetes Service Types: ClusterIP, NodePort, LoadBalancer
July 7, 2026 · 10 min read
In Kubernetes, Pods are ephemeral — they die, restart, and change IPs. A Service puts a stable access point in front of a group of Pods. But where you can reach it from depends on the Service type. There are three main types.
ClusterIP (default)
Gives a virtual IP reachable only from inside the cluster. Closed to the outside world. Ideal for microservices talking to each other — e.g. an API reaching its database.
NodePort
Opens a specific port (30000-32767) on every node for your app. You can reach it externally via <node-ip>:<port>. Simple but crude for production — usually used for dev/test or behind a load balancer.
LoadBalancer
Provisions a real external load balancer from your cloud provider (AWS, GCP, Azure) and gives a single public IP. It's the standard way to receive external traffic in production.
apiVersion: v1
kind: Service
metadata:
name: web
spec:
type: LoadBalancer
selector:
app: web
ports:
- port: 80
targetPort: 8080Which one, when?
- ClusterIP: internal service-to-service traffic (default)
- NodePort: quick testing or custom network setups
- LoadBalancer: exposing a single service to the internet in production
- For many HTTP services: Ingress + ClusterIP (one LB, many routes)
Case: 'I can't reach my Service' — diagnosis
You created a Service but curl times out. 90% of the time the cause is: the Service selector matches no Pods (so Endpoints is empty). The diagnosis flow:
- 1kubectl get endpoints <svc> → if empty, the selector doesn't match
- 2kubectl get pods --show-labels → do Pod labels equal the Service selector?
- 3Does targetPort match the port the container actually listens on?
- 4Test from inside the cluster (before changing the external type)
$ kubectl get svc webNAME TYPE CLUSTER-IP PORT(S) AGEweb ClusterIP 10.96.0.20 80/TCP 3m$ kubectl get endpoints webNAME ENDPOINTS AGEweb <none> 3m # ⚠ empty! The selector matches no Pod.$ kubectl get pods --show-labelsweb-xyz 1/1 Running app=web-api # Pod label is 'app=web-api'# Service selector is 'app=web' → mismatch. Fix the selector:$ kubectl get endpoints webNAME ENDPOINTS AGEweb 10.244.0.7:8080,10.244.0.8:8080 1m # ✓ now populated$ kubectl run tmp --rm -it --image=busybox -- wget -qO- web:80<h1>OK</h1> # ✓ in-cluster access works
Note
Golden rule: for a connectivity problem, check 'kubectl get endpoints' FIRST. If it's empty, the problem is selector/label matching, not the Service type (NodePort/LB). Changing the type won't fix it.
Mini task
Create a Deployment (app=web) + a ClusterIP Service but deliberately set a wrong selector (app=api). See that Endpoints is empty, confirm access from a busybox Pod fails, fix the selector and restore access.
Hands-on task — try it in your browser
Trying these types on a real cluster and watching traffic makes the concept stick — exactly what Cloudpuz's Kubernetes labs offer.
Official sources
Last verified: 2026-07-17
Frequently Asked Questions
What is a Service in Kubernetes?
In Kubernetes, Pods are ephemeral: they die, restart, and change IPs. A Service puts a stable access point in front of a group of Pods. But where you can reach the app from depends on the chosen Service type.
What is the difference between ClusterIP, NodePort, and LoadBalancer?
ClusterIP gives a virtual IP reachable only from inside the cluster and is closed to the outside world. NodePort opens a port in the 30000-32767 range on every node, reachable externally via `<node-ip>:<port>`. LoadBalancer provisions a real external load balancer from your cloud provider and gives a single public IP.
Which Kubernetes Service type should you use, and when?
ClusterIP is used for internal service-to-service traffic and is the default. NodePort suits quick testing or custom network setups. LoadBalancer is the standard way to expose a single service to the internet in production; for many HTTP services, use Ingress + ClusterIP (one LB, many routes).
I can't reach my Kubernetes Service — how do I diagnose it?
About 90% of the time the cause is that the Service selector matches no Pods, so Endpoints is empty. First run `kubectl get endpoints <svc>`; if empty, the selector doesn't match. Then use `kubectl get pods --show-labels` to check whether Pod labels equal the Service selector, and confirm targetPort matches the port the container actually listens on.
Does changing the Service type fix a connectivity problem in Kubernetes?
No. For a connectivity problem you should check `kubectl get endpoints` first; if it's empty, the problem is selector/label matching, not the Service type (NodePort/LoadBalancer). Changing the type won't fix it.
Reading isn't enough — do it.
Practice these topics in an interactive terminal in your browser.