What is a Kubernetes Service? ClusterIP, NodePort, LoadBalancer Explained Simply
Pods can die and restart with new IPs. A Service gives them a stable address. Here's how ClusterIP, NodePort, and LoadBalancer actually work — with clear examples.
A pod dies. Kubernetes starts a new one. The new pod gets a different IP address. Any other pod that was talking to the old IP address now gets connection refused.
This is why Kubernetes Services exist.
What a Service Does
A Service is a stable network endpoint that sits in front of one or more pods. It has:
- A fixed ClusterIP that never changes
- A DNS name (auto-created)
- A selector that defines which pods it routes to
When pods die and restart with new IPs, the Service automatically updates its routing. Everything talking to the Service keeps working.
┌─────────────┐ ┌─────────────────────┐
│ Other Pod │ ─────→ │ Service (stable IP) │ ─────→ Pods
│ (10.244.1.5)│ │ (10.96.45.100) │ (any IP)
└─────────────┘ └─────────────────────┘
The Four Service Types
1. ClusterIP (Default)
Accessible only inside the cluster. Not reachable from outside.
apiVersion: v1
kind: Service
metadata:
name: my-api
spec:
selector:
app: my-api
ports:
- port: 80 # Port the Service listens on
targetPort: 8080 # Port the pod listens on
type: ClusterIP # Default — can omit this lineDNS name: my-api.default.svc.cluster.local
Short form: my-api (within same namespace)
# From another pod inside the cluster:
curl http://my-api/health
curl http://my-api.default.svc.cluster.local/health
# From outside the cluster: NOT accessibleUse when: Internal service-to-service communication. Database services. Internal APIs.
2. NodePort
Opens a specific port on every node in the cluster. Traffic to <NodeIP>:<NodePort> reaches your pods.
apiVersion: v1
kind: Service
metadata:
name: my-api
spec:
selector:
app: my-api
ports:
- port: 80
targetPort: 8080
nodePort: 30080 # Port on the actual node (30000–32767)
type: NodePort# Accessible from outside using any node's IP:
curl http://192.168.1.10:30080 # Node 1
curl http://192.168.1.11:30080 # Node 2 — same resultUse when: Quick testing on local clusters (kind, minikube). Simple external access without a cloud load balancer.
Don't use in production — exposes ports on every node, hard to manage at scale.
3. LoadBalancer
Provisions an actual cloud load balancer (AWS ALB/NLB, GCP Load Balancer, Azure LB). Gets an external IP.
apiVersion: v1
kind: Service
metadata:
name: my-api
spec:
selector:
app: my-api
ports:
- port: 80
targetPort: 8080
type: LoadBalancerkubectl get svc my-api
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
# my-api LoadBalancer 10.96.45.100 34.100.200.150:80 80:30080/TCP
# External IP is your cloud load balancer's IP
curl http://34.100.200.150/healthUse when: You need external access in a cloud environment. Each LoadBalancer service creates one cloud LB (expensive at scale).
For multiple services: Use Ingress instead of multiple LoadBalancer services.
4. ExternalName
Maps a Service to an external DNS name. No proxying — just DNS CNAME.
apiVersion: v1
kind: Service
metadata:
name: my-database
spec:
type: ExternalName
externalName: mydb.rds.amazonaws.comPods inside the cluster can now reach my-database and it resolves to your RDS endpoint.
Use when: Abstracting external services so pods don't need to hardcode external hostnames.
How Services Find Pods: Selectors and Endpoints
Services use label selectors to find pods:
# Service selector
spec:
selector:
app: my-api
environment: production
# Pod must have matching labels
metadata:
labels:
app: my-api
environment: production# See which pods a service is routing to
kubectl get endpoints my-api -n <namespace>
# NAME ENDPOINTS AGE
# my-api 10.244.1.5:8080,10.244.2.3:8080 5m
# If ENDPOINTS shows <none> → labels don't matchThe most common mistake: typo in the selector label. Always check endpoints when a service isn't routing.
Service DNS — How Pods Find Each Other
Every Service gets a DNS entry automatically via CoreDNS:
<service-name>.<namespace>.svc.cluster.local
Examples:
# From a pod, reaching the "payments" service in "billing" namespace:
curl http://payments.billing.svc.cluster.local/api/charge
# Short form (same namespace only):
curl http://payments/api/charge
# Environment variables also injected (older method):
# PAYMENTS_SERVICE_HOST=10.96.100.50
# PAYMENTS_SERVICE_PORT=80ClusterIP vs NodePort vs LoadBalancer — Decision Table
| Scenario | Service Type |
|---|---|
| Pod-to-pod internal traffic | ClusterIP |
| Testing on local Kubernetes (kind/minikube) | NodePort |
| Production external access (cloud) | LoadBalancer + Ingress |
| Abstracting external DB/service | ExternalName |
| Multiple HTTP services behind one IP | Ingress (not Service type) |
Quick Debugging
# Service not routing? Check endpoints:
kubectl get endpoints <service-name>
# DNS not resolving? Test from a pod:
kubectl exec -it <any-pod> -- nslookup <service-name>
# See service details:
kubectl describe svc <service-name>
# Port mismatch? Check targetPort matches container port:
kubectl get pod <pod> -o yaml | grep containerPortServices are one of the most fundamental Kubernetes concepts. Once you understand ClusterIP vs NodePort vs LoadBalancer, everything else in networking (Ingress, Gateway API) builds on top of this foundation.
For hands-on Kubernetes networking labs, KodeKloud has CKA-prep courses that cover Services, Endpoints, DNS, and Ingress in depth.
Stay ahead of the curve
Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.
Related Articles
How to Migrate from Ingress-NGINX to Kubernetes Gateway API in 2026
Step-by-step guide to migrating from Ingress-NGINX to Kubernetes Gateway API. Includes YAML examples, implementation choices, testing strategy, and cutover plan.
How to Set Up Kubernetes Gateway API to Replace Ingress (2026 Guide)
The Kubernetes Ingress API is being replaced by the Gateway API. Here's a complete step-by-step guide to setting it up with Nginx Gateway Fabric and migrating from Ingress.
What is a Service Mesh? Explained Simply (No Jargon)
Service mesh sounds complicated but the concept is simple. Here's what it actually does, why teams use it, and whether you need one — explained without the buzzwords.