Day 9of40daysofkubernetes : Comparing Kubernetes Services: ClusterIP, NodePort, LoadBalancer, ExternalName
In Kubernetes, services play a vital role in enabling communication between different components of an application. A Service in Kubernetes is an abstraction that defines a logical set of Pods and a policy by which to access them. Since Pods are ephemeral and have dynamic IPs, services provide a consistent way to expose these Pods to other Pods or external users.
Kubernetes offers several types of services to handle different network access scenarios, each serving distinct use cases. In this blog, we’ll break down four essential service types: ClusterIP, NodePort, LoadBalancer, and ExternalName.
1. ClusterIP: Internal Communication
Overview:
ClusterIP is the default service type in Kubernetes, designed for internal communication within the cluster. It automatically assigns an internal IP address to the service, making it accessible only from within the cluster.
Use Case:
This service is ideal for microservices that need to communicate internally within the Kubernetes cluster. For example, one service like a backend might need to access a database that is hosted inside the cluster using a ClusterIP service.
Key Characteristics:
Internal Only: Services are exposed to the cluster internally, not externally.
Automatic IP: Kubernetes automatically assigns an IP for internal use.
No External Access: Pods outside the cluster cannot access a ClusterIP service directly.
Example YAML:
apiVersion: v1
kind: Service
metadata:
name: my-clusterip-service
spec:
type: ClusterIP
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
2. NodePort: Expose Service on Each Node’s IP
Overview:
NodePort builds on top of ClusterIP but extends accessibility by opening a specific port on each node in the cluster. This service type allows external traffic to access the service via the node’s IP address and a designated port.
Use Case:
NodePort is used when you want to expose your service outside the cluster, but you don’t want or need a load balancer. It can be handy for development environments or simple setups where direct access to node IPs is feasible.
Key Characteristics:
Fixed Port Range: NodePort assigns a port from the default range (30000–32767) on each node.
Cluster-wide Access: Any node in the cluster can accept traffic on the assigned port.
Limited Traffic Distribution: Traffic is routed to any node but not load-balanced like a LoadBalancer service.
Example YAML:
apiVersion: v1
kind: Service
metadata:
name: my-nodeport-service
spec:
type: NodePort
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
nodePort: 32000
3. LoadBalancer: Expose via External Load Balancer
Overview:
LoadBalancer service type is designed for production environments where you want to expose a service to the outside world through an external load balancer. It builds upon NodePort and ClusterIP, but with added support from cloud providers (e.g., AWS, GCP, Azure) to provision a load balancer automatically.
Use Case:
This service type is often used for publicly exposed applications, such as a web app or API endpoint, where traffic needs to be evenly distributed across multiple pods for redundancy and scalability.
Key Characteristics:
Cloud Provider Integration: Automatically provisions an external load balancer through cloud infrastructure.
Direct External Access: The service is accessible via the load balancer’s external IP.
Load Balancing: Traffic is evenly distributed across multiple nodes and pods.
Higher Cost: LoadBalancers typically incur extra costs depending on the cloud provider.
Example YAML:
apiVersion: v1
kind: Service
metadata:
name: my-loadbalancer-service
spec:
type: LoadBalancer
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
4. ExternalName: Map Service to External DNS Name
Overview:
ExternalName service type is a unique kind of service that does not involve IP-based routing like the other types. Instead, it maps a service to an external DNS name, effectively acting as an alias for external services.
Use Case:
This service is useful when you need to access external services by DNS name, such as external databases, APIs, or third-party services, from within the cluster without using ClusterIP or NodePort.
Key Characteristics:
No Pods or Endpoints: Doesn’t route traffic within the cluster but simply maps a DNS name to an external service.
DNS Resolution: Pods within the cluster use Kubernetes DNS to resolve the external name.
No Load Balancing: No load balancing or traffic management is involved.
Example YAML:
apiVersion: v1
kind: Service
metadata:
name: external-service
spec:
type: ExternalName
externalName: api.external-service.com
Key Differences and Use Cases:
Service Type | Access Scope | Use Case | Pros | Cons |
ClusterIP | Internal | Internal microservice communication | Simple, fast internal routing | No external access |
NodePort | External | Expose services on each node’s IP and port | Simple external access | Not suitable for large-scale external traffic |
LoadBalancer | External (via Load Balancer) | Production-grade external access via cloud LB | Cloud provider handles load balancing and access | Extra cost, tied to cloud provider |
ExternalName | External DNS | Access external services by DNS from within the cluster | Simplifies access to external services | Limited use case, no traffic management |
Task
1. Create a Service of type ClusterIP
First, create a Service named myapp
of type ClusterIP
that exposes port 80 and maps to the target port 80.
apiVersion: v1
kind: Service
metadata:
name: myapp
spec:
type: ClusterIP
selector:
app: myapp
ports:
- protocol: TCP
port: 80
targetPort: 80
2. Create a Deployment with 1 replica of nginx:1.23.4-alpine
Now, create a Deployment named myapp
with 1 replica using the nginx:1.23.4-alpine
image and exposing the container port 80.
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 1
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: nginx
image: nginx:1.23.4-alpine
ports:
- containerPort: 80
After creating the deployment, expose the container port using the same label selector as in the service.
3. Scale the Deployment to 2 replicas
To scale the deployment to 2 replicas, run the following command:
kubectl scale deployment myapp --replicas=2
This increases the number of pods running your nginx
container to 2.
4. Create a Temporary Pod Using busybox
and Run a wget
Command
To create a temporary pod with the busybox
image and run a wget
command against the service, use the following command:
kubectl run busybox --rm -it --image=busybox -- /bin/sh
Once inside the container shell, find the ClusterIP of the service:
kubectl get svc myapp
Now run the wget
command:
wget -O- <ClusterIP>:80
This command should display the HTML content served by your nginx
service.
5. Run a wget
Command Against the Service Outside the Cluster
Currently, the ClusterIP
type service is not accessible from outside the cluster. You can verify that by trying to access it from an external machine using the service IP, but the connection will fail since it is an internal-only service.
6. Change the Service Type to Allow External Access
To allow external access to the service, change the service type to NodePort
:
kubectl patch svc myapp -p '{"spec": {"type": "NodePort"}}'
Alternatively, update the YAML and apply it:
apiVersion: v1
kind: Service
metadata:
name: myapp
spec:
type: NodePort
selector:
app: myapp
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 32000 # This can be in the range 30000-32767
7. Run wget
Against the Service from Outside the Cluster
Once the service is exposed via NodePort
, you can access the service by using the IP address of any node in your Kubernetes cluster along with the NodePort
assigned to the service (32000 in this example):
wget -O- <NodeIP>:32000
This command should retrieve the HTML page from the nginx
server running inside your cluster.
Conclusion
Each Kubernetes service type has its own strengths and weaknesses, making them suitable for different scenarios. Choosing the right service depends on your needs: for internal communication, go with ClusterIP; for simple external access, consider NodePort; for production-grade external access, LoadBalancer is a great choice; and if you need to access external services, ExternalName fits the bill.
Understanding these options is crucial in deploying scalable, accessible, and reliable Kubernetes applications effectively.
References
Subscribe to my newsletter
Read articles from Rahul Vadakkiniyil directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by