How Does a ClusterIP Service Work in Kubernetes?

beginner|servicesdevopssreCKACKAD
TL;DR

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:

  1. DNS Resolution -- CoreDNS resolves backend-api (or backend-api.production.svc.cluster.local) to the ClusterIP 10.96.112.34.

  2. Packet Interception -- The packet destined for 10.96.112.34:80 hits the iptables or IPVS rules programmed by kube-proxy on the node where the client Pod is running.

  3. 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).

  4. 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

Can you access a ClusterIP Service from outside the cluster?
Not directly. You would need to use kubectl port-forward, an Ingress controller, or change the Service type to NodePort or LoadBalancer to expose it externally.
What is the difference between port and targetPort in a ClusterIP Service?
The port field is the port the Service listens on (the ClusterIP port). The targetPort is the port on the Pod container where traffic is forwarded. They can be different values.
How is the ClusterIP address assigned?
The API server allocates a ClusterIP from the configured service-cluster-ip-range CIDR. You can also specify a static IP using the spec.clusterIP field, as long as it falls within the valid range.

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.