#KubeWeek Challenge Day-4
Kubernetes Services and Service Discovery

#KubeWeek Challenge Day-4 Kubernetes Services and Service Discovery

# how to expose Kubernetes workloads to the outside world using Services. # how to discover Services and Pods within a Kubernetes cluster using DNS.

Expose Kubernetes workloads to the outside world using Service:

Services in Kubernetes:

A Kubernetes Service is a Kubernetes object which enables cross-communication between different components within and outside a Kubernetes cluster. It exposes Kubernetes applications to the outside world while simultaneously allowing network access to a set of Pods within and outside of a Kubernetes cluster.

Why Services and Not Pod IP?

The Pod IP address is dynamic, which means it could change any moment. For example, when a Pod crashes or is deleted and another one comes up with the help of a ReplicaSet, the new Pod has a different IP address from the terminated one. This makes the Pod IP address unstable which can result in application errors. However, managing a connection to a Pod with a Service creates a stable IP address to reach the Pod.

Service Types:

There are five different types of Service:

  1. ClusterIP (default)

  2. Node Port

  3. ExternalName

  4. Headless

  5. Load balancer

Creating a Service with ClusterIP:

Step 1: First, create a Deployment and make sure that the spec.selector.matchLabels.app value in the Deployment manifest file matches the spec.template.metadata.labels.app value in the same Deployment manifest as well as the spec.selector.app value in the Service manifest file. The manifest file will look like this:

apiVersion: apps/v1 
kind: Deployment 
metadata: 
 name: my-deployment 
spec: 
 replicas: 2 
 strategy: 
  type: Recreate 
 selector: 
  matchLabels: 
   app: my-app 
 template: 
   metadata: 
    labels: 
     app: my-app 
     env: prod 
   spec: 
    containers: 
    - name: my-deployment-container 
      image: nginx

Use kubectl create command to create the Deployment. This configuration will create a Deployment with two Pods that we will expose with a ClusterIP service. Once the Pods are running by checking it using kubectl get pods command, create a Service with the below configuration:

Step 2: Create the Service

Create a YAML file:

vim clp_service.yaml
apiVersion: v1
kind: Service
metadata:
 name: example-prod
spec:
 selector:
   app: my-app
   env: prod
 type: ClusterIP
 ports:
 - protocol: TCP
   port: 80
   targetPort: 8080

Step 3: Deploy your Service to the cluster.

kubectl create -f clp_service.yaml

Step 4: Make sure both your Pods and the Service are running by checking their statuses.

Check the status of the service:

kubectl get service example-prod
NAME               TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)      AGE
example-prod       ClusterIP   10.107.61.93  <none>     80/TCP        13s

Check the status of the Pods to get their names:

kubectl get pods
NAME                             READY   STATUS    RESTARTS   AGE
my-deployment-6b9b97d749-g5d2w   1/1     Running   0          10m
my-deployment-6b9b97d749-w9tq5   1/1     Running   0          10m

Step 5: Determine the Service IP and Port.
Exec into one of the containers:

kubectl exec -it my-deployment-6b9b97d749-g5d2w -- bin/bash
root@my-deployment-6b9b97d749-g5d2w:

Check the Service info in the Container:

root@my-deployment-97cfc859f-q9dqh:/#  printenv | grep SERVICE
KUBERNETES_SERVICE_HOST=10.96.0.1  
KUBERNETES_SERVICE_PORT=44
KUBERNETES_SERVICE_PORT_HTTPS=443

As can be seen above, the created Service was not part of the output. Why? This will be the case if you create the Deployment before the Service. You can simply correct it by deleting all the instances of the Pod so that they can be re-created when the Service is already running.

$ kubectl delete pod my-deployment-6b9b97d749-g5d2w my-deployment-6b9b97d749-w9tq5
pod "my-deployment-6b9b97d749-g5d2w" deleted
pod "my-deployment-6b9b97d749-w9tq5" deleted

Check the status of the Pods:

$ kubectl get pods
NAME                                READY     STATUS     RESTARTS   AGE
my-deployment-6b9b97d749-48d27      1/1       Running    0          21s
my-deployment-6b9b97d749-gsrwp      1/1       Running    0          21s

Exec into one of the Containers again:

$ kubectl exec -it my-deployment-6b9b97d749-48d27 -- bin/bash

root@my-deployment-6b9b97d749-48d27:/#

Check the Service info in the Container:

root@my-deployment-6b9b97d749-48d27:/#  printenv | grep SERVICE
KUBERNETES_SERVICE_PORT_HTTPS=443 ## Default Service name and Port on the Cluster
KUBERNETES_SERVICE_PORT=443
EXAMPLE_PROD_SERVICE_HOST=10.107.61.93 ##Service IP as shown in the Service status
KUBERNETES_SERVICE_HOST=10.96.0.1 ## Kubernetes IP already on the cluster
EXAMPLE_PROD_SERVICE_PORT=80 ##Service name and Port specified in the Service YAML file.

As can be seen here, the Service name, Port, and host values are output in the container. This is possible because both the Service and the Pod are running on the same Cluster and the Service was created before the Pod/Deployment.


Discover Services and Pods within a Kubernetes cluster using DNS:

  • Kubernetes provides built-in DNS-based service discovery, allowing services and pods to communicate with each other using DNS names.

  • By default, each Service in a Kubernetes cluster is assigned a DNS name based on its name and namespace.

  • Similarly, pods are assigned a DNS name based on their name and namespace.

Discovering a Service using DNS:

Let's say we have a Service named "my-service" deployed in the "default" namespace. We can discover this Service using DNS. Here's an example Python code snippet to resolve the DNS and retrieve the IP address of the Service:

import socket

service_host = "my-service.default.svc.cluster.local"
service_port = 80

service_address = socket.gethostbyname(service_host)
print(f"Service IP: {service_address}")

In the above code snippet, replace my-service with the actual name of your Service, and modify the namespace and port accordingly. Running this code will resolve the DNS name my-service.default.svc.cluster.local and print the corresponding IP address of the Service.

Discovering a Pod using DNS:

Similarly, let's assume we have a Pod named "my-pod" running in the "default" namespace. We can discover this Pod using DNS. Here's an example Python code snippet to resolve the DNS and retrieve the IP address of the Pod:

import socket

pod_host = "my-pod.default.pod.cluster.local"
pod_port = 8080

pod_address = socket.gethostbyname(pod_host)
print(f"Pod IP: {pod_address}")

Replace my-pod with the actual name of your Pod, and adjust the namespace and port as necessary. Executing this code will resolve the DNS name my-pod.default.pod.cluster.local and display the IP address of the Pod.

To test the above code snippets, ensure that you have the necessary Python environment set up with the socket module available. Execute the code and observe the output, which will provide the IP addresses of the discovered Service and Pod.

Note: Remember to replace the placeholder values (my-service, my-pod, default, etc.) in the code snippets with the actual names and namespaces of your Services and Pods within the Kubernetes cluster.

Thank you for reading!Happy Learning!!

Santosh Chauhan

Did you find this article valuable?

Support Santosh Chauhan's blog by becoming a sponsor. Any amount is appreciated!