Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

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.

Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – REST with Spring (eBook) (everywhere)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.