ClusterIP
The default Kubernetes Service type that assigns a stable virtual IP address accessible only within the cluster, enabling internal pod-to-pod communication through a consistent endpoint that remains fixed regardless of underlying pod IP changes.
ClusterIP — The Internal Backbone of Kubernetes Service Discovery
What is ClusterIP in Simple Terms?
Pods are temporary — they get new IP addresses every time they restart. ClusterIP gives your service a permanent internal address that never changes. Other pods always connect to this stable ClusterIP and Kubernetes handles routing to the actual pods behind it.
Service Types Comparison
+---------------+--------------------------------------------------+| Type | Accessibility |+---------------+--------------------------------------------------+| ClusterIP | Internal only — accessible only inside cluster || NodePort | Opens a port on every node — external access || LoadBalancer | Creates a cloud load balancer — full external || ExternalName | Maps to an external DNS name |+---------------+--------------------------------------------------+How ClusterIP Routes Traffic
+---------------------+ +----------------------+| payments-api pod | | ClusterIP Service || (10.244.1.20) | | (10.96.45.200:4000)|+---------------------+ +----------------------+ | +---------------------------+---------------------------+ | | | v v v+---------------------+ +---------------------+ +---------------------+| payments pod | | payments pod | | payments pod || 10.244.1.21:4000 | | 10.244.2.15:4000 | | 10.244.3.8:4000 |+---------------------+ +---------------------+ +---------------------+kube-proxy manages iptables rules on every node to distribute traffic across the pods behind the ClusterIP.
Example ClusterIP Service
# service.yaml — internal service for the payments APIapiVersion: v1kind: Servicemetadata: name: payments-service namespace: productionspec: type: ClusterIP # Default — no need to specify explicitly selector: app: payments-api # Routes to pods with this label ports: - protocol: TCP port: 4000 # Port the service listens on targetPort: 4000 # Port the container actually runs onHow to Inspect a ClusterIP Service
# Get service details including the assigned ClusterIPkubectl get service payments-service -n production # Output:# NAME TYPE CLUSTER-IP PORT(S) AGE# payments-service ClusterIP 10.96.45.200 4000/TCP 5d # See which pods are backing this service via endpointskubectl get endpoints payments-service -n production # Full describe for troubleshootingkubectl describe service payments-service -n productionTroubleshooting ClusterIP
| Symptom | Likely Cause | Fix |
|---|---|---|
| Connection refused on ClusterIP | No pods match the selector | Check kubectl get endpoints — empty means label mismatch |
| ClusterIP unreachable from outside | Expected — it is internal only | Use kubectl port-forward for local debugging |
| Intermittent failures | Some pods are unhealthy | Check pod readiness probes |
| DNS name not resolving | CoreDNS issue | Run kubectl exec -it <pod> -- nslookup payments-service.production |
# Debug ClusterIP connectivity from inside a podkubectl exec -it debug-pod -n production -- curl http://payments-service.production:4000/health # Temporarily expose ClusterIP to local machine for debuggingkubectl port-forward service/payments-service 4000:4000 -n productionRememberClusterIP addresses are virtual — they exist only in iptables rules managed by kube-proxy. You cannot ping a ClusterIP directly from outside the cluster.
TipUse
kubectl port-forward service/payments-service 4000:4000 -n productionto temporarily expose a ClusterIP service to your local machine for debugging without changing the service type.
Common MistakeChanging the
portvalue in a service spec without updating all internal consumers. Every other service or pod that callspayments-service:4000will break immediately. Always treat ClusterIP port values as a contract between services in production at Razorpay or PhonePe scale.
Frequently Asked Questions
If ClusterIP is only reachable inside the cluster, how does external traffic ever reach a pod?
It doesn't, directly — that's the point. ClusterIP is the building block: a NodePort or LoadBalancer Service is layered on top of (or alongside) the same selector to expose it externally, or an Ingress controller routes external traffic to a ClusterIP Service internally. Most internal microservice-to-microservice traffic never needs anything more than ClusterIP, since it's the cheapest and most secure option — no exposure surface at all outside the cluster.
What's a common ClusterIP troubleshooting mistake?
Assuming a ClusterIP Service is broken when the real issue is a label selector mismatch — the Service's selector doesn't match any pod's labels, so it has zero endpoints and silently drops all traffic with no error. Always check `kubectl get endpoints <service>` before debugging DNS or networking; an empty endpoints list means the Service and pods were never actually connected, regardless of how correctly the Service itself is configured.