ClusterIP
ClusterIP is the default and most common Service type in Kubernetes. It provides a stable, cluster-internal IP address that allows pods and other cluster resources to communicate with a set of pods. Think of ClusterIP as an internal phone number—it works perfectly within your organization (cluster), but external callers can’t reach it directly.
What is ClusterIP?
A ClusterIP Service creates a virtual IP address that’s only accessible from within the Kubernetes cluster. This IP address is stable—it doesn’t change even if the pods behind it are recreated, rescheduled, or scaled. The Service automatically load balances traffic across all pods matching its selector.
How ClusterIP Works
When you create a ClusterIP Service, Kubernetes:
- Allocates a virtual IP from the cluster’s service CIDR (typically
10.96.0.0/12) - Creates DNS records for service discovery
- Watches for matching pods using the Service selector
- Updates Endpoints as pods are added or removed
- Routes traffic using kube-proxy on each node
ClusterIP Service Example
Here’s a basic ClusterIP Service:
apiVersion: v1
kind: Service
metadata:
name: web-service
namespace: default
spec:
type: ClusterIP # This is the default, can be omitted
selector:
app: web
tier: frontend
ports:
- port: 80
targetPort: 8080
protocol: TCP
Key points:
type: ClusterIPis the default—you can omit itselectormust match labels on your podsportis the Service port (what clients connect to)targetPortis the pod container port (where traffic is forwarded)
Service IP Allocation
ClusterIP addresses are allocated from the cluster’s service CIDR range, which is configured when the cluster is set up. The IPs are managed by Kubernetes and remain stable for the lifetime of the Service.
DNS Discovery
ClusterIP Services are automatically discoverable via DNS. Within the same namespace, you can use the short name:
# Pod connecting to Service
apiVersion: v1
kind: Pod
metadata:
name: client-pod
spec:
containers:
- name: app
image: busybox
command: ['sh', '-c', 'wget -O- http://web-service:80']
DNS resolution:
- Short name:
web-service(same namespace) - FQDN:
web-service.default.svc.cluster.local(any namespace) - Cross-namespace:
web-service.production.svc.cluster.local
Load Balancing
ClusterIP Services automatically distribute traffic across all healthy pods matching the selector. The default load balancing algorithm is round-robin, but the exact behavior depends on the kube-proxy mode (iptables, ipvs, or userspace).
Complete Example: Frontend to Backend
Here’s a complete example showing a frontend Service connecting to a backend Service:
Backend Deployment and Service:
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
spec:
replicas: 3
selector:
matchLabels:
app: backend
template:
metadata:
labels:
app: backend
spec:
containers:
- name: api
image: my-api:1.0
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: backend-service
spec:
selector:
app: backend
ports:
- port: 80
targetPort: 8080
Frontend Deployment using Backend Service:
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
replicas: 2
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: web
image: my-frontend:1.0
env:
- name: BACKEND_URL
value: "http://backend-service:80" # Uses ClusterIP Service
ports:
- containerPort: 3000
---
apiVersion: v1
kind: Service
metadata:
name: frontend-service
spec:
selector:
app: frontend
ports:
- port: 80
targetPort: 3000
Multiple Ports
ClusterIP Services can expose multiple ports:
apiVersion: v1
kind: Service
metadata:
name: multi-port-service
spec:
selector:
app: my-app
ports:
- name: http
port: 80
targetPort: 8080
protocol: TCP
- name: https
port: 443
targetPort: 8443
protocol: TCP
- name: metrics
port: 9090
targetPort: 9090
protocol: TCP
Clients can connect to specific ports:
http://multi-port-service:80→ pod port 8080https://multi-port-service:443→ pod port 8443http://multi-port-service:9090→ pod port 9090
Session Affinity
By default, ClusterIP Services distribute requests across pods. You can enable session affinity to route requests from the same client to the same pod:
apiVersion: v1
kind: Service
metadata:
name: sticky-service
spec:
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
sessionAffinity: ClientIP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 10800 # 3 hours
Use cases:
- Applications that store session data in memory
- Sticky sessions for stateful workloads
- Applications that benefit from connection reuse
When to Use ClusterIP
Use ClusterIP when:
✅ Internal communication - Services that only need to be accessed from within the cluster
✅ Microservices architecture - Service-to-service communication
✅ Database connections - Internal database access (don’t expose databases externally)
✅ API backends - Backend APIs consumed by frontend services
✅ Default choice - When you don’t need external access, ClusterIP is the right choice
Don’t use ClusterIP when:
- You need external internet access
- You’re running on bare metal without a load balancer
- You need direct external client access
ClusterIP vs Other Service Types
Best Practices
- Use ClusterIP by default - It’s the most secure and appropriate for internal services
- Don’t expose databases externally - Use ClusterIP for databases, access via bastion or VPN
- Use descriptive Service names - Names should indicate the service purpose
- Match selectors exactly - Ensure Service selector matches pod labels precisely
- Document port mappings - Clearly document which Service ports map to which pod ports
- Use port names - Name ports for clarity, especially with multiple ports
- Test DNS resolution - Verify Services are discoverable via DNS
- Monitor Endpoints - Ensure Services are finding and routing to the correct pods
Troubleshooting
Service Not Accessible
- Check Service exists:
kubectl get service <service-name> - Verify Endpoints:
kubectl get endpoints <service-name>- should list pod IPs - Check selector matches pods:
kubectl get pods -l app=my-app - Test DNS resolution:
kubectl run -it --rm debug --image=busybox --restart=Never -- nslookup <service-name>
DNS Not Resolving
- Use FQDN: Try
<service>.<namespace>.svc.cluster.localinstead of short name - Check namespace: Ensure client and Service are in the same namespace (or use FQDN)
- Verify CoreDNS:
kubectl get pods -n kube-system -l k8s-app=kube-dns
Traffic Not Reaching Pods
- Check targetPort: Verify
targetPortmatches the container’s listening port - Test pod directly:
kubectl port-forward <pod-name> <port>to test pod connectivity - Check pod logs: Verify pods are running and listening on the expected port
- Verify Endpoints:
kubectl describe endpoints <service-name>to see which pods are included
Connection Refused
- Pod not listening: Check if the container is actually listening on
targetPort - Wrong port: Verify the
targetPortin Service matches container port - Pod not ready: Check pod readiness probes and status
See Also
- Services Overview - Introduction to Kubernetes Services
- NodePort - Exposing Services externally via node IPs
- LoadBalancer - Cloud provider load balancers
- Endpoints & EndpointSlice - How Services track pods
- DNS & CoreDNS - Service discovery via DNS