Skip to main content

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

◈ DIAGRAM
+---------------+--------------------------------------------------+
| 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

◈ DIAGRAM
+---------------------+ +----------------------+
| 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

YAML
# service.yaml — internal service for the payments API
apiVersion: v1
kind: Service
metadata:
name: payments-service
namespace: production
spec:
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 on

How to Inspect a ClusterIP Service

Bash
# Get service details including the assigned ClusterIP
kubectl 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 endpoints
kubectl get endpoints payments-service -n production
# Full describe for troubleshooting
kubectl describe service payments-service -n production

Troubleshooting 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
Bash
# Debug ClusterIP connectivity from inside a pod
kubectl exec -it debug-pod -n production -- curl http://payments-service.production:4000/health
# Temporarily expose ClusterIP to local machine for debugging
kubectl port-forward service/payments-service 4000:4000 -n production
Remember

ClusterIP addresses are virtual — they exist only in iptables rules managed by kube-proxy. You cannot ping a ClusterIP directly from outside the cluster.

Tip

Use kubectl port-forward service/payments-service 4000:4000 -n production to temporarily expose a ClusterIP service to your local machine for debugging without changing the service type.

Common Mistake

Changing the port value in a service spec without updating all internal consumers. Every other service or pod that calls payments-service:4000 will 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.