Kubernetes PODS & SERVICES Discovery
Tags: kubernetes, devops, kcdchennai
Published: 2023-05-25 13:38:26

## Introduction✍️

In this particular blog, we are going to talk about how all these workloads can be exposed outside to the world with the help of these Services and DNS. So that external users can also access your application.

## How to expose Kubernetes workloads to the outside world using Services?🌏

Before heading to these topics you must have the knowledge of all the workloads.

### Pre-requisites👇
PODS📦
DNS🧑‍💻
Services⚙️

Services are available in three main types:

- ClusterIP

- NodePort

- LoadBalancer

ClusterIP is the default service created by k8s. With the help of this type, you can access your application just within your cluster. It will provide you with the benefit of load balancing and discovery, which we will learn about in the below section in detail.

If you want to check all your created services, use get command:


![svc](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g5plplu46bneau3lghrh.png)


Also, you can write with the alias:

`kubectl` aka `k`

`services` aka `svc`


![k s](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/102c8x0ki8ad9s0b9i3n.png)


Trust me, this saves a lot of time.🥺

And also, I have covered the file creation already in detail.

`NodePort` can provide you to access your application within the cluster as well as to those who have access to the worker nodes you have set up during the creation.

Creating a `service` of `NodePort` type, the `/root/service-definition-1.yaml` file as follows:

```
---
apiVersion: v1
kind: Service
metadata:
  name: webapp-service
  namespace: default
spec:
  ports:
  - nodePort: 30080
    port: 8080
    targetPort: 8080
  selector:
    name: simple-webapp
  type: NodePort
```
Run the following command to create a `webapp-service` service as follows: -

`kubectl apply -f /root/service-definition-1.yaml`


![svc](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b8lqqfth0pc87g4o55np.png)


> Create the service-definition-1.yaml -> Add the service template using vi/vim -> Edit the details in the file -> Use command apply to create it

I am not going into details about the types of services because I have covered everything in my previous blog learnings.🫣

We will only be focusing on:

### Exposing Kubernetes workloads to the outside world👶

`LoadBalancer` is the type of service that will expose your application to outside the world.

This will only work on **cloud providers**. There will be an elastic load balancer that will be created by the cloud providers which is a public IP address through which you can access your application.

**Cloud Control Manager** which is inside your master node will generate public IP adders using any cloud provider eg AWS and returns to the service so that anyone can access your application using that IP address.

To create a service obviously, we need all the pods and `deployment-definition` file.

So here it is:

```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: webapp
  template:
    metadata:
      labels:
        app: webapp
    spec:
      containers:
      - name: webapp
        image: my/webapp:latest
        ports:
        - containerPort: 80
```
Now, time to create a `service-definition-2` yaml file with `LoadBalance` type:

```
apiVersion: v1
kind: Service
metadata:
  name: webapp-service
spec:
  selector:
    app: webapp
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 80
  type: LoadBalancer
```
First run,

`kubectl apply -f /root/service-definition-2.yaml`

Now the service is created. You can access this through the internet with the correct IP address and port number provided by this service.

Check the IP address and Ports by `get` command:

`kubectl get svc <name>`

## How to discover Services and Pods within a Kubernetes cluster using DNS and other mechanisms?🧐

As we know how service works and its purpose But did you think how it tackled the problems? How does it send requests to the users? How does it provide everything requested by the users?

Let's see the solution:

**Service** act as a **load balancer** by using a component known as `kube-proxy`.

So instead of accessing the IP addresses, it helps the users to give a specific service name to the users to access the application.

`kube-proxy` will forward the requests coming from several users.

So without Services, your application will not work even if you have everything like pods, deployments, etc ready. When a pod goes down then you're unable to provide your applications to the users in case of no service available.

But the question remains the same. How service is handling the IP addresses, as every time a pod goes down, it comes up with a different address. So how this is going on?

If three of the pods are deployed in the cluster and each one has its IP address and whenever a pod goes down and comes up always with the new IPs then how service is managed all the time with the new IPs and managing all the user's requests?

This is handled by Service Discovery.

### Service Discovery🕵️

This comes up with a new process called **Labels** & **Selectors**

Instead of working with IP addresses and keeping track of it. Service is using the concept of labels & selectors.

### Labels📋

- It is just a key-value pair.

- You can name it by your conventions.

- It is used to organize and select the objects in the cluster

- You can label Pods, Deployments, and Services.

- Example, `key=app` and `value=myapp`

```
metadata:
  labels:
    app: myapp
```
### Selectors✅

- It must be defined same name as the labels defined.

- It is used to select objects based on their labels.

- It can be used for a single or a groped objects that matches specific labels.

- Example, create a Service that selects all Pods with the label `app=myapp`:

```
yamlCopy codespec:
  selector:
    app: myapp
```
We will give labels in our pod definition yaml file so that whenever a pod goes down and comes up with new IPs, it will always have the same label in it as we defined in the template. A new pod is always created with the given template.

- The replica sets will deploy the pods using the **labels**.

- **Services** will keep track of all the deployments by the labels.

- **Labels** are just a name given to a pod nothing else.

So this is the service discovery mechanism that uses labels & selectors.

So you created a deployment definition yaml file and on that the metadata section you will define a label which can be any name provided by you for your deployed application.

### Pod Discovery Using DNS🌐

The **CoreDNS** server is deployed as a POD in `kube-system` namespace in the k8s cluster.

It creates a service to make it available to other components within a cluster. And the service is named `kube-dns` by default.

`kubectl get service -n kube-system`

It uses a file called **Corefile** which is located at `/etc/coredns`

`cat /etc/coredns/Corefile`

In this file, you have all the configurations of plugins.

One of the plugins that make `CoreDNS` work with k8s is the Kubernetes plugin.

A top-level domain name is set as a `cluster.local`

The **DNS** configuration on **PODS** is done by k8s automatically when the pod is created.

`config` file of the `kubelet` will give you the IP of the DNS server and the domain:

`cat /var/lib/kubelet/config.yml`

You can access your `service` by just

`name-service` or

`name-service.default` or

`name-service.default.svc` or

`name-service.default.svc.cluster.local`

`<service-name>.<namespace>.svc.cluster.local`

Example, `service-name=mywebapp` and `namespace=default` which is created automatically as default. Then,

`mywebapp.default.svc.cluster.local`

If you try to manually lookup for the service using `nslookup` or the host command

`host <name-service>`

### Pod Discovery Using Environment Variables🔗

The container which has the information of Services and PODS that are running inside the k8s cluster has an environment variable automatically set by Kubernetes.

These variables are used to discover the IP address, port numbers and hostname for the services and running pods.

Example,

the `SERVICE_HOST` and `SERVICE_PORT` environment variables are automatically set in containers running inside a Service's Pod.

the `HOSTNAME` environment variable is set to the hostname of the Pod and the `MY_POD_IP` environment variable is set to the Pod's IP address.

Let's create a simple `service` yaml file to use for further process with type `ClusterIP`:

```
apiVersion: v1
kind: Service
metadata:
  name: myapp-service
  labels:
    app: myapp
spec:
  type: ClusterIP
  selector:
    app: myapp
  ports:
  - name: http
    port: 80
    targetPort: 8080
```
Now, let's create a `pod` YAML file that runs `image=nginx` by setting two `env` variables `MYAPP_SERVICE_HOST` and `MYAPP_POD_IP`

```
apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
  - name: myapp-container
    image: nginx
    env:
    - name: MYAPP_SERVICE_HOST
      value: "myapp-service.default.svc.cluster.local"
    - name: MYAPP_POD_IP
      valueFrom:
        fieldRef:
          fieldPath: status.podIP
```
`MYAPP_SERVICE_HOST` is set to `myapp.default.svc.cluster.local` and

`MYAPP_POD_IP` is set using a `fieldRef` that retrieves the Pod's IP address from its status.

Together, these files define a web application that can be accessed using the virtual IP address assigned to the Service.

When a client sends a request to the Service's IP address on port 80, the request will be forwarded to one of the Pods with the `app: myapp` label and the response will be sent back to the client.

This is how you can discover pods using environment variables.

---

Thank you!🖤