Cluster IP service is the default service type that gets created when you create a Kubernetes service.

Here’s what it looks like:

NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
demo         ClusterIP   10.100.68.216    <none>        80/TCP           161m

The Cluster IP is a stable IP address that remains unchanged throughout the lifetime of the service.

Though this service may point to multiple pods that can come and go, but you can always access them through the service’s single and constant IP address.

We already saw it in action in another post where we created a Kubernetes service and accessed it using another pod.

But how can a client pod directly know the IP and port of a service? It’s not a great experience where you first create the service, then manually look up its IP address and pass the IP to the configuration options of the client pod.

This is where Kubernetes service discovery comes in really handy.

There are two ways you can access Cluster IP service in Kubernetes from another pod in the cluster:

  • Pod Environment Variables
  • Kubernetes DNS system

In this post, I will discuss both and show you how to use them.

1 – Pod Environment Variables

When you start a pod, Kubernetes initializes a bunch of environment variables. These variables point to each service that exists at that moment. You can use the variable to directly access the service without knowing the ClusterIP.

So, what’s the catch?

The catch is that if you create the service after creating the pods, the pod isn’t going to get those environment variables. In other words, you must:

  • Create the ClusterIP service
  • Then, create the pods supported by the service.

To check whether a pod has the environment variables, execute the below command.

$ kubectl exec basic-rc-86w4j env

Here, basic-rc-86w4j is the name of the pod.

You should a big list of variables printed on the screen. The environment variables for the Kubernetes service will look like below:

DEMO_SERVICE_HOST=10.100.68.216
DEMO_PORT_80_TCP_PROTO=tcp
DEMO_SERVICE_PORT=80
DEMO_PORT_80_TCP_PORT=80
DEMO_PORT=tcp://10.100.68.216:80
DEMO_PORT_80_TCP=tcp://10.100.68.216:80
DEMO_PORT_80_TCP_ADDR=10.100.68.216

How can you use these environment variables?

That’s simple.

The environment variables are available to the process running within the pod. For example, in the case of Node.js, you can pull out any of these variables from the process.env object. Then, it’s a matter of using it in your application as per the requirement.

Check the below example for reference where we access the variable DEMO_SERVICE_HOST from process.env object:

const express = require('express');

const app = express();

let requestCount = 0;

console.log(`Service Host: ${process.env.DEMO_SERVICE_HOST}`);

app.get('/', (req, res) => {
    requestCount++;
    if (requestCount > 2) {
        res.status(500).send("The app is not well. Please restart!")
    }
    res.send("Hello World from our Kubernetes Pod Demo")
})

app.listen(3000, () => {
    console.log("Listening to requests on Port 3000")
})

2 – DNS for Cluster IP Kubernetes Service

The first approach works well.

But looking up IP address and port is usually the job of a DNS system.

Kubernetes has its own DNS server that you can use to access the service without worrying about the IP address and port.

In your Kubernetes installation, there is a special namespace named kube-system. Within that namespace, there is a special service kube-dns. Behind the service are a couple of pods that run a DNS server known as Core DNS.

Here’s a quick command to check it out:

saurabhdashora@Saurabhs-MacBook-Air basic-pod-demo % kubectl --namespace=kube-system get svc                                                     
NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
kube-dns   ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   256d

All other pods running in the cluster are automatically configured to use this DNS service. Each service gets a DNS entry in the internal DNS server. The client pods just need to known the name of the service and they can access it through its fully qualified domain name (aka FQDN)

Whenever a process running in a pod makes a DNS query, it comes to the Kubernetes DNS server.

For example, if I want to access the demo-service, I can open a connection to the below FQDN:

demo.default.svc.cluster.local

Here,

  • demo is the name of the service.
  • default stands for the namespace the service is defined in
  • svc.cluster.local is a configurable cluster domain suffix used in all cluster local service names.

In fact, connecting to the service is even simpler. You can omit the svc.cluster.local suffix as well as the namespace when the two pods are in the same namespace. In other words, you can simply refer to the service as demo.

See the below example:

$ kubectl exec basic-rc-86w4j -- curl http://demo

What makes this possible is the DNS resolver inside each pod’s container. You can check out how the resolver works by inspecting /etc/resolv.conf file.

saurabhdashora@Saurabhs-MacBook-Air basic-pod-demo % kubectl exec basic-rc-86w4j -- cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

Conclusion

With this, we have looked at two ways to access a Cluster IP service in Kubernetes from another pod.

  • Using Pod Environment Variables
  • Using the in-built Kubernetes DNS server

This is the simplest use-case for accessing a service and also quite common way of quickly setting up connections between services running on different pods.

Hope you found it useful. In future posts, I’ll be covering other ways of connecting to Kubernetes services.

Categories: BlogKubernetes

Saurabh Dashora

Saurabh is a Software Architect with over 12 years of experience. He has worked on large-scale distributed systems across various domains and organizations. He is also a passionate Technical Writer and loves sharing knowledge in the community.

0 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *