K8s Service Types: ClusterIP NodePort LB
Kubernetes Service types explained: ClusterIP, NodePort, LoadBalancer, and ExternalName. When to use each type with YAML examples and traffic flow diagrams.
π‘ Quick Answer: Kubernetes has 4 Service types: ClusterIP (internal-only, default) β accessible within the cluster via virtual IP. NodePort β exposes on every nodeβs IP at a static port (30000-32767). LoadBalancer β provisions cloud load balancer with external IP. ExternalName β DNS CNAME alias to external service. Choose ClusterIP for microservice communication, NodePort for dev/testing, LoadBalancer for production external access.
The Problem
Pods are ephemeral β their IPs change on restart. Services provide:
- Stable virtual IP for a set of pods
- Load balancing across pod replicas
- DNS-based service discovery
- External access to cluster workloads
But which Service type fits your use case?
The Solution
ClusterIP (Default)
apiVersion: v1
kind: Service
metadata:
name: api-service
spec:
type: ClusterIP # default, can be omitted
selector:
app: api
ports:
- port: 80 # Service port
targetPort: 8080 # Pod port[Pod A] β api-service:80 β [api pod 1]
β [api pod 2]
β [api pod 3]
# Only accessible within the cluster
# DNS: api-service.default.svc.cluster.localUse when: microservices communicating within the cluster.
Headless Service (ClusterIP: None)
apiVersion: v1
kind: Service
metadata:
name: db-service
spec:
clusterIP: None # Headless β no virtual IP
selector:
app: postgres
ports:
- port: 5432# DNS returns individual pod IPs instead of virtual IP
nslookup db-service
# db-service.default.svc.cluster.local β 10.244.1.5
# β 10.244.2.3
# Used by StatefulSets for stable network identitiesNodePort
apiVersion: v1
kind: Service
metadata:
name: web-nodeport
spec:
type: NodePort
selector:
app: web
ports:
- port: 80
targetPort: 8080
nodePort: 30080 # Optional, auto-assigned if omitted (30000-32767)[External] β <any-node-ip>:30080 β [web pod 1]
β [web pod 2]
# Accessible from outside via any node's IP
# Port range: 30000-32767Use when: development, testing, bare-metal clusters without cloud LB.
LoadBalancer
apiVersion: v1
kind: Service
metadata:
name: web-lb
annotations:
# Cloud-specific annotations
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
spec:
type: LoadBalancer
selector:
app: web
ports:
- port: 80
targetPort: 8080[Internet] β Cloud LB (external IP) β [web pod 1]
β [web pod 2]
# Cloud provider provisions a load balancer
# kubectl get svc β EXTERNAL-IP: 34.123.45.67Use when: production external access on cloud providers (AWS, GCP, Azure).
Bare-metal: Use MetalLB to provide LoadBalancer functionality.
ExternalName
apiVersion: v1
kind: Service
metadata:
name: external-db
spec:
type: ExternalName
externalName: db.example.com# DNS CNAME β no proxy, no port mapping
nslookup external-db
# external-db.default.svc.cluster.local β CNAME db.example.comUse when: aliasing external services with cluster DNS names.
Comparison Table
| Type | External Access | IP Type | Port Range | Cloud Required |
|---|---|---|---|---|
| ClusterIP | β Internal only | Virtual IP | Any | No |
| NodePort | β Via node IP | Node IPs | 30000-32767 | No |
| LoadBalancer | β External IP | Cloud LB IP | Any | Yes (or MetalLB) |
| ExternalName | β DNS alias | None | N/A | No |
| Headless | β Internal only | Pod IPs directly | Any | No |
Quick Create Commands
# ClusterIP
kubectl expose deployment nginx --port=80 --target-port=8080
# NodePort
kubectl expose deployment nginx --type=NodePort --port=80 --target-port=8080
# LoadBalancer
kubectl expose deployment nginx --type=LoadBalancer --port=80 --target-port=8080
# Generate YAML
kubectl expose deployment nginx --port=80 --dry-run=client -o yamlCommon Issues
LoadBalancer stuck in βPendingβ EXTERNAL-IP
No cloud LB controller. On bare-metal, install MetalLB: kubectl apply -f https://metallb.io/manifests.
NodePort not reachable
Firewall blocking port range 30000-32767. Open these ports on cloud security groups or iptables.
Service has no endpoints
Selector doesnβt match any pod labels. Check: kubectl get endpoints <svc>.
Best Practices
- ClusterIP for 90% of services β internal microservice communication
- Ingress/Gateway API over NodePort/LoadBalancer β one LB for many services
- Headless for StatefulSets β stable network identity per pod
- Set
externalTrafficPolicy: Localon NodePort/LB β preserves client IP - Use annotations for cloud LB tuning β NLB vs ALB, internal vs external
Key Takeaways
- ClusterIP is the default β internal-only, stable virtual IP
- NodePort opens a port on every node (30000-32767) β good for dev
- LoadBalancer provisions cloud infrastructure β production external access
- ExternalName creates DNS CNAME aliases to external services
- Most production apps use ClusterIP + Ingress (one LB for many services)

Recommended
Kubernetes Recipes β The Complete Book100+ production-ready patterns with detailed explanations, best practices, and copy-paste YAML. Everything in one place.
Get the Book βLearn by Doing
CopyPasteLearn β Hands-on Cloud & DevOps CoursesMaster Kubernetes, Ansible, Terraform, and MLOps with interactive, copy-paste-run lessons. Start free.
Browse Courses βπ Deepen Your Skills β Hands-on Courses
Courses by CopyPasteLearn.com β Learn IT by Doing
