ClusterIP in Kubernetes
As the default service type that gives a logical group of Pods a reliable, internal-only virtual IP address, ClusterIP forms the basis of internal networking in Kubernetes. In a dynamic Kubernetes cluster, pods are generated, removed, or transferred between nodes and given a new IP address each time. Direct Pod communication is unreliable due to its transience. In order to ensure that internal application components may interact dependably regardless of the underlying Pod lifecycle, ClusterIP acts as a permanent network endpoint, which includes a persistent virtual IP, a DNS name, and a certain port.
How ClusterIP Works
Kubernetes assigns a virtual IP address from a reserved internal CIDR range upon the definition of a ClusterIP service. This address can only be accessible from within the virtual network of the cluster; it cannot be directly accessed by other clients or the public internet.
The mechanism depends on a number of crucial elements:
- Label Selectors: The service chooses which Pods to send its traffic to using selectors. The service automatically adds any Pod with labels that meet the selector to its endpoint pool.
- Kube-Proxy: Each cluster node runs
kube-proxy.Kube-proxyredirects ClusterIP queries to a functional backend Pod’s IP address using iptables or IPVS rules. - EndpointSlices: By continuously monitoring healthy Pods that meet the selection, the Kubernetes control plane updates EndpointSlices, an extension of the existing Endpoints API, with the latest service destination IPs.
- Load Balancing: ClusterIP’s built-in load balancing rounds-robins incoming requests among all healthy backup Pods.
You can also read How to create a Service in Kubernetes & It’s Core Mechanisms
Service Discovery: DNS and Environment Variables
How other programs locate ClusterIP is one of its most potent features. Kubernetes offers two main ways to find information:
- DNS (Recommended): The service name is automatically mapped to its assigned ClusterIP by the integrated DNS service (CoreDNS). A pod can access a namespace service (
backend-service) by name. For cross-namespace communication, the Fully Qualified Domain Name (FQDN) is used in the format:<service-name>.<namespace>.svc.cluster.local. - Environment Variables: During Pod startup, the
kubeletinserts environment variables{SVCNAME}_SERVICE_HOSTand{SVCNAME}_SERVICE_PORTfor each active service in the cluster. This technique requires building the service before the client Pods.
IP Allocation Strategies
There are two methods Kubernetes can assign a virtual IP address to a service:
Dynamically: For type: ClusterIP Services, the control plane of the cluster automatically selects a free IP address from the configured IP range.
Statically, you designate an IP address that falls inside the Services’ specified IP range.
All of your cluster’s Service ClusterIP need to be distinct. An error will be returned if you attempt to build a service using a ClusterIP that has already been assigned.
You can also read What is the Importance of Kubernetes & Why Kubernetes?
Why do you need to reserve Service Cluster IPs?
In certain cases, you might want to operate services on well-known IP addresses so that users and other cluster components can utilize them.
The cluster’s DNS service is the finest illustration. Some Kubernetes installers assign the DNS service the tenth IP address from the Service IP range as a soft convention. If your cluster has the Service IP range 10.96.0.0/16 and you wanted your DNS service IP to be 10.96.0.10, you would need to establish a service like this:
apiVersion: v1
kind: Service
metadata:
labels:
k8s-app: kube-dns
kubernetes.io/cluster-service: "true"
kubernetes.io/name: CoreDNS
name: kube-dns
namespace: kube-system
spec:
clusterIP: 10.96.0.10
ports:
- name: dns
port: 53
protocol: UDP
targetPort: 53
- name: dns-tcp
port: 53
protocol: TCP
targetPort: 53
selector:
k8s-app: kube-dns
type: ClusterIP
The IP address 10.96.0.10 has not been reserved. There is a possibility that other services will be able to assign this IP if they are established prior to or concurrently with dynamic allocation. Because of the conflict error, you won’t be able to establish the DNS service.
How can you avoid Service ClusterIP conflicts?
The collision risk is decreased by the allocation mechanism used by Kubernetes to assign ClusterIPs to Services.
The formula min(max(16, cidrSize / 16), 256) is used to divide the ClusterIP range, which is defined as never being less than 16 or greater than 256 with a graduated step between them.
By default, dynamic IP assignment uses the top band; after this is used up, it will use the lower range. Users will be able to employ static allocations on the lower band with less collision risk thanks to this.
You can also read What is Kubernetes Architecture, Features of K8s
Examples of ClusterIP Implementation
Internal Backend Microservice
A typical microservices architecture requires communication between a backend API and a frontend application. The internet shouldn’t be connected to the backend pods.
YAML Definition:
apiVersion: v1
kind: Service
metadata:
name: backend-service
spec:
type: ClusterIP
selector:
app: backend-app
ports:
- name: http
protocol: TCP
port: 80 # Port exposed by the service
targetPort: 8080 # Port the backend application is listening on in the Pod
By submitting queries to http://backend-service:80, any Pod in the cluster can access the backend in this scenario. The traffic is then sent by the service to port 8080 on one of the Pods with the label app: backend-app.
Database Connectivity
For internal databases that need to be protected from outside access, such as MySQL or PostgreSQL, ClusterIP is the recommended option.
YAML Definition:
apiVersion: v1
kind: Service
metadata:
name: mysql-service
spec:
type: ClusterIP
selector:
app: mysql-db
ports:
- port: 3306
targetPort: 3306
An environment variable like DB_HOST=mysql-service can be used to configure a web application, such as WordPress. Even if the database Pod is relocated to a different node, the application will always be able to access its database because the internal DNS resolves mysql-service to the stable ClusterIP.
Headless Services for Stateful Applications
Sometimes you want to reach individual Pods directly rather to use load balancing or a single virtual IP (common for distributed databases like Cassandra). By specifying clusterIP: None, a Headless Service can be created.
YAML Definition:
apiVersion: v1
kind: Service
metadata:
name: database-headless
spec:
clusterIP: None # Defines this as a headless service
selector:
app: my-db
ports:
- port: 5432
In this scenario, a DNS lookup for database-headless will return all backing Pods’ direct IP addresses rather than just one virtual IP, giving the client the option to select which Pod to connect to.
Multi-Port Services
Certain applications must provide multiple endpoints, like one for metrics scraping and another for user traffic. As long as each port has a distinct name, ClusterIP lets you declare several ports inside of a single service object.
YAML Definition:
apiVersion: v1
kind: Service
metadata:
name: app-service
spec:
selector:
app: web-app
ports:
- name: http
port: 80
targetPort: 8080
- name: metrics
port: 9090
targetPort: 9090
With this arrangement, the same reliable virtual IP address is used for two different internal endpoints.
Conclusion and Best Practices
Kubernetes networking relies heavily on ClusterIP to provide the essential decoupling between services. It is recommended by best practices to always use DNS names instead of hardcoding IP addresses because the DNS name doesn’t change even if a service is removed and recreated with a new IP. Additionally, although while ClusterIP offers rudimentary load balancing, Readiness Probes should be used in conjunction with it to guarantee that traffic is only sent to Pods that are healthy and completely initialized. A stable and secure internal microservices architecture is made possible by ClusterIP, which abstracts away the transient nature of individual Pods.
You can also read What is Container Orchestration in Kubernetes?
