How Does a ClusterIP Service Work in Kubernetes?
ClusterIP is the default Service type in Kubernetes. It assigns a virtual IP address reachable only from within the cluster, making it the standard choice for internal microservice-to-microservice communication.
What Is a ClusterIP Service?
A ClusterIP Service is the default Service type in Kubernetes. When you create a Service without specifying a type, Kubernetes automatically creates a ClusterIP Service. It assigns a virtual IP address from the cluster's internal IP range, and that address is only routable from within the cluster.
This makes ClusterIP the go-to choice for internal communication between microservices, such as a frontend Pod talking to a backend API or an application connecting to a cache layer.
Creating a ClusterIP Service
apiVersion: v1
kind: Service
metadata:
name: backend-api
namespace: production
spec:
type: ClusterIP
selector:
app: backend-api
tier: backend
ports:
- name: http
protocol: TCP
port: 80
targetPort: 8080
Once applied:
kubectl get svc backend-api -n production
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
backend-api ClusterIP 10.96.112.34 <none> 80/TCP 12s
The CLUSTER-IP column shows the virtual IP. The EXTERNAL-IP column is <none> because ClusterIP Services are not externally accessible.
How Traffic Flows
When a client Pod sends a request to backend-api:80, the following happens:
-
DNS Resolution -- CoreDNS resolves
backend-api(orbackend-api.production.svc.cluster.local) to the ClusterIP10.96.112.34. -
Packet Interception -- The packet destined for
10.96.112.34:80hits the iptables or IPVS rules programmed by kube-proxy on the node where the client Pod is running. -
DNAT -- The rules perform Destination NAT, rewriting the destination IP and port to one of the backend Pod IPs (e.g.,
10.244.2.15:8080). -
Delivery -- The packet is routed through the cluster's CNI network to the selected backend Pod.
┌─────────────┐ DNS: 10.96.112.34 ┌──────────────────┐
│ Client Pod │ ──────────────────────────>│ iptables/IPVS │
│ │ dst: 10.96.112.34:80 │ on client node │
└─────────────┘ └────────┬─────────┘
│ DNAT
┌────────▼─────────┐
│ Backend Pod │
│ 10.244.2.15:8080│
└──────────────────┘
Specifying a Static ClusterIP
By default, Kubernetes allocates a random IP from the service CIDR range. You can request a specific IP:
apiVersion: v1
kind: Service
metadata:
name: backend-api
spec:
type: ClusterIP
clusterIP: 10.96.100.50
selector:
app: backend-api
ports:
- port: 80
targetPort: 8080
This is useful when you have legacy systems or configuration files that reference a fixed IP. The requested IP must fall within the cluster's --service-cluster-ip-range.
ClusterIP: None (Headless Service)
Setting clusterIP: None creates a headless Service. Instead of allocating a virtual IP, DNS returns the individual Pod IPs directly. This is covered in depth in the headless services question, but here is the declaration:
apiVersion: v1
kind: Service
metadata:
name: backend-api-headless
spec:
type: ClusterIP
clusterIP: None
selector:
app: backend-api
ports:
- port: 80
targetPort: 8080
Headless Services are critical for StatefulSets where clients need to address specific Pods.
Multiple Ports
A ClusterIP Service can expose several ports simultaneously:
apiVersion: v1
kind: Service
metadata:
name: backend-api
spec:
selector:
app: backend-api
ports:
- name: http
port: 80
targetPort: 8080
- name: metrics
port: 9090
targetPort: 9090
- name: grpc
port: 50051
targetPort: 50051
Each port gets its own entry in the Endpoints object, and kube-proxy programs rules for all of them.
Debugging a ClusterIP Service
When a ClusterIP Service is not working, follow this checklist:
# 1. Verify the Service exists and has a ClusterIP
kubectl get svc backend-api
# 2. Check endpoints -- are any Pods registered?
kubectl get endpoints backend-api
# 3. Verify Pods are running and have matching labels
kubectl get pods -l app=backend-api
# 4. Test connectivity from within the cluster
kubectl run debug --rm -it --image=busybox -- wget -qO- http://backend-api:80
# 5. Check kube-proxy logs for errors
kubectl logs -n kube-system -l k8s-app=kube-proxy --tail=50
The most common issue is an empty Endpoints list, which means the selector does not match any running Pod.
When to Use ClusterIP
| Scenario | Suitable? |
|---|---|
| Microservice-to-microservice calls | Yes |
| Database or cache accessed only from within the cluster | Yes |
| API exposed to external users | No -- use NodePort, LoadBalancer, or Ingress |
| Development with kubectl port-forward | Yes (port-forward to ClusterIP works) |
Performance Considerations
ClusterIP routing relies on kube-proxy. The two main modes have different performance profiles:
- iptables mode -- Uses probabilistic rules for load balancing. Works well for small-to-medium clusters. Rule updates get slower with thousands of Services.
- IPVS mode -- Uses kernel-level hash tables for O(1) lookups. Preferred for large clusters with many Services and endpoints.
You can check the current mode:
kubectl get configmap kube-proxy -n kube-system -o yaml | grep mode
Summary
ClusterIP is the workhorse of Kubernetes networking. It provides a stable internal endpoint for Pod-to-Pod communication, backed by DNS and kube-proxy rules. Nearly every Kubernetes cluster relies on ClusterIP Services as the default building block, with other Service types layering additional functionality on top of it.
Why Interviewers Ask This
ClusterIP is the most commonly used Service type, and interviewers want to confirm candidates understand internal networking fundamentals before moving on to more complex external-facing Service types.
Common Follow-Up Questions
Key Takeaways
- ClusterIP is the default and most commonly used Service type, providing internal-only access.
- The virtual IP is stable for the lifetime of the Service and is backed by iptables or IPVS rules on every node.
- ClusterIP Services get DNS records automatically, enabling service discovery by name.