1. Overview
Networking is an integral part of Kubernetes, with Service being one of its primitive networking objects. Kubernetes Service allows us to expose a network application to the external world. However, to access it, we must know its URL.
In this hands-on tutorial, we’ll discuss finding and using the Kubernetes service’s URL as a reliable network endpoint.
2. Setting up an Example
We need to create a few Kubernetes objects to use as an example. To begin, let’s create Namespace objects.
2.1. Creating Kubernetes Namespaces
Kubernetes namespaces allow us to isolate the resources within the same cluster. So, let’s use the create command to create two namespaces – dev and stg:
$ kubectl create ns dev
namespace/dev created
$ kubectl create ns stg
namespace/stg created
2.2. Creating Kubernetes Deployments
In the previous step, we created two namespaces. Now, let’s deploy the Redis pod to those namespaces:
$ kubectl create deploy redis-dev --image=redis:alpine -n dev
deployment.apps/redis-dev created
$ kubectl create deploy redis-stg --image=redis:alpine -n stg
deployment.apps/redis-stg created
Next, let’s verify that the pods have been created and that they’re in a healthy state:
$ kubectl get pods -n dev
NAME READY STATUS RESTARTS AGE
redis-dev-7b647c797c-c2mmg 1/1 Running 0 16s
$ kubectl get pods -n stg
NAME READY STATUS RESTARTS AGE
redis-stg-d66978466-plfpv 1/1 Running 0 9s
Here, we can observe that the status of both pods is Running.
Now, the required setup is ready. In the upcoming sections, we’ll create a few Service objects to establish communication with these pods.
3. Finding the URL of the ClusterIP Service
In Kubernetes, the default service type is ClusterIP. For ClusterIP services, we can use the service name or its IP address as its URL. This allows us to limit communication only within the cluster. Let’s understand this with a simple example.
3.1. Creating the ClusterIP Services
First, let’s create ClusterIP Service objects in both namespaces:
$ kubectl expose deploy redis-dev --port 6379 --type ClusterIP -n dev
service/redis-dev exposed
$ kubectl expose deploy redis-stg --port 6379 --type ClusterIP -n stg
service/redis-stg exposed
In this example, we’ve used the expose command to create a Service object. The expose command uses the selectors of the Deployment object and creates a Service using the same selectors.
In the following sections, we’ll discuss how to find and use the names of these services as URLs.
3.2. Using the URL of the ClusterIP Service in the Same Namespace
First, let’s use the get command to find the service name from the dev namespace:
$ kubectl get svc -n dev
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
redis-dev ClusterIP 10.100.18.154 <none> 6379/TCP 9s
In the output, the first column shows the service name. In our case, it’s redis-dev.
Now, let’s exec to the Redis pod that is deployed in the dev namespace, connect to the Redis server using redis-dev as a hostname, and execute the PING command:
$ kubectl exec -it redis-dev-7b647c797c-c2mmg -n dev -- sh
/data # redis-cli -h redis-dev PING
PONG
/data # exit
Here, we can see that the Redis server responds with the PONG message.
Finally, we execute the exit command to exit from the pod.
3.3. Using the URL of the ClusterIP Service From Another Namespace
Let’s examine the format of a ClusterIP service URL:
<service-name>.<namespace>.<cluster-name>:<service-port>
We didn’t use the namespace and cluster-name in the previous example because we executed the command from the same namespace and cluster. In addition to that, we also skipped service-port because the Service was exposed using the default Redis port 6379.
However, we need to specify a namespace name to use the ClusterIP service from another namespace. Let’s understand this with an example.
First, let’s find out the name of the service in the stg namespace:
$ kubectl get svc -n stg
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
redis-stg ClusterIP 10.110.213.51 <none> 6379/TCP 9s
Now, let’s exec to the Redis pod that is deployed in the dev namespace, connect to the Redis server using redis-stg.stg as a hostname, and execute the PING command:
$ kubectl exec -it redis-dev-7b647c797c-c2mmg -n dev -- sh
/data # redis-cli -h redis-stg.stg PING
PONG
/data # exit
In this example, we can see that the Redis server sends a PONG reply.
An important thing to note is that we’ve used redis-stg.stg as a hostname, where redis-stg is the service name and stg is the namespace name in which the Service object was created.
3.4. Cleaning Up
In the previous examples, we saw how to use the Service name as the URL.
Now, let’s use the delete command to clean up the services from the dev and stg namespaces:
$ kubectl delete svc redis-dev -n dev
service "redis-dev" deleted
$ kubectl delete svc redis-stg -n stg
service "redis-stg" deleted
4. Finding the URL of the NodePort Service
The NodePort service allows external connectivity to the application using the IP address and port of the Kubernetes node. Let’s understand this by creating a NodePort service.
4.1. Creating the NodePort Service
First, let’s use the expose command to create a Service with the type NodePort:
$ kubectl expose deploy redis-dev --port 6379 --type NodePort -n dev
service/redis-dev exposed
Next, let’s verify that the Service has been created:
$ kubectl get svc -n dev
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
redis-dev NodePort 10.111.147.176 <none> 6379:30243/TCP 2s
Here, we can see that the Service type is NodePort. In the second-to-last column, it shows that the Kubernetes node’s port 30243 is mapped to the pod’s port 6379.
Now, we can use the IP address of the Kubernetes node and port 30243 from outside the cluster to access the Redis server. Let’s see this in action.
4.2. Using the URL of the NodePort Service
First, let’s find the IP address of the Kubernetes node:
$ kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
baeldung Ready control-plane 24h v1.28.3 192.168.49.2 <none> Ubuntu 22.04.3 LTS 5.15.0-41-generic docker://24.0.7
Here, we’ve used the -o wide option with the Node objects to show the additional fields.
In the above output, the column with the header INTERNAL-IP shows the Kubernetes node’s IP address.
Now, from the external machine, let’s connect to the Redis server using 192.168.49.2 as a hostname, 30243 as a port number, and execute the PING command:
$ redis-cli -h 192.168.49.2 -p 30243 PING
PONG
Here, we can see that the Redis server responds with a PONG message.
4.3. Cleaning Up
In the next section, we’re going to see the usage of the LoadBalancer service. But before that, let’s do the cleanup of the NodePort service from the dev namespace:
$ kubectl delete svc redis-dev -n dev
service "redis-dev" deleted
5. Finding the URL of the LoadBalancer Service
Just like the NodePort service, the LoadBalancer service also allows external connectivity to the application using the load balancer’s IP address. To understand this, let’s create a LoadBalancer service:
5.1. Creating the LoadBalancer Service
Let’s use the expose command to create a LoadBalancer service in the dev namespace:
$ kubectl expose deploy redis-dev --port 6379 --type LoadBalancer -n dev
service/redis-dev exposed
5.2. Using the URL of the LoadBalancer Service
Next, let’s use the get command to find the load balancer’s IP address:
$ kubectl get svc -n dev
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
redis-dev LoadBalancer 10.111.167.249 192.168.49.10 6379:32637/TCP 7s
In this example, the column with the header EXTERNAL-IP represents the LoadBalancer service’s IP address.
In our case, the load balancer’s IP address is 192.168.49.10.
Now, from the external machine, let’s connect to the Redis server using 192.168.49.10 as a hostname and execute the PING command:
$ redis-cli -h 192.168.49.10 PING
PONG
In the output, we can see that the Redis server replies with a PONG message.
6. Cleaning Up
Deleting all unwanted objects to tidy up the cluster is a good practice. This helps us in lowering our costs by reducing hardware consumption.
So, let’s use the delete command to remove the dev and stg namespaces:
$ kubectl delete ns dev
namespace "dev" deleted
$ kubectl delete ns stg
namespace "stg" deleted
This command deletes the namespace itself and all objects that are present in this namespace.
Here, we deleted namespaces directly, as this is the test setup. However, we should be very careful while performing delete operations in the production environment.
7. Conclusion
In this article, we discussed how to find and use the URL of a service in Kubernetes.
First, we saw how to use the ClusterIP service name as a URL from the same and another namespace. Then, we discussed how to find and use the URL of the NodePort service.
Finally, we discussed using the load balancer’s IP address as a service URL.