Day-37-devops

Understanding Kubernetes Services: Load Balancing, Service Discovery, and Application Exposure

TLDR: This blog post provides a comprehensive overview of Kubernetes services, focusing on load balancing, service discovery, and how to expose applications to both internal and external users. It includes practical demonstrations using Cube Shark to visualize traffic flow within a Kubernetes cluster.

In this blog post, we will dive deep into Kubernetes services, exploring their functionalities and practical applications. We will cover load balancing, service discovery, and how to expose applications to the outside world. This session will include practical demonstrations using Cube Shark, a tool that helps visualize traffic flow within a Kubernetes cluster.

What are Kubernetes Services?

Kubernetes services are an abstraction that defines a logical set of pods and a policy by which to access them. They enable communication between different components of a Kubernetes application, ensuring that traffic is routed correctly and efficiently.

Key Functions of Kubernetes Services

  1. Load Balancing: Distributing incoming traffic across multiple pods to ensure no single pod is overwhelmed.

  2. Service Discovery: Allowing pods to find and communicate with each other without needing to know their IP addresses.

  3. Application Exposure: Making applications accessible to users both inside and outside the Kubernetes cluster.

Practical Demonstration

Setting Up the Kubernetes Cluster

For our demonstration, we will use a Minikube Kubernetes cluster. If you are unfamiliar with setting up a Kubernetes cluster, refer to previous tutorials that cover creating a cluster using Minikube or AWS.

Creating a Deployment

We will start by creating a deployment for a simple Python application. The deployment will manage the pods and ensure that the desired number of replicas are running. Here’s how to create a deployment:

  1. Build the Docker Image: Create a Docker image for the Python application.

     docker build -t python-sample-app:v1 .
    
  2. Create the Deployment YAML: Define the deployment in a deployment.yaml file, specifying the number of replicas and labels.

     apiVersion: apps/v1
     kind: Deployment
     metadata:
       name: sample-python-app
     spec:
       replicas: 2
       selector:
         matchLabels:
           app: sample-python-app
       template:
         metadata:
           labels:
             app: sample-python-app
         spec:
           containers:
           - name: python-app
             image: python-sample-app:v1
             ports:
             - containerPort: 8000
    
  3. Apply the Deployment: Use the following command to create the deployment in the Kubernetes cluster.

     kubectl apply -f deployment.yaml
    

Creating a Service

Next, we will create a service to expose our deployment. We will demonstrate both NodePort and LoadBalancer service types.

NodePort Service

  1. Define the Service YAML: Create a service.yaml file for the NodePort service.

     apiVersion: v1
     kind: Service
     metadata:
       name: python-django-app-service
     spec:
       type: NodePort
       selector:
         app: sample-python-app
       ports:
         - port: 80
           targetPort: 8000
           nodePort: 30007
    
  2. Apply the Service: Create the service using the command:

     kubectl apply -f service.yaml
    
  3. Access the Application: You can access the application using the Node IP and NodePort.

     curl http://<Node-IP>:30007/demo
    

LoadBalancer Service

To expose the application to external users, we can change the service type to LoadBalancer. However, this requires a cloud provider.

  1. Edit the Service: Change the service type in the service.yaml file to LoadBalancer.

     spec:
       type: LoadBalancer
    
  2. Apply the Changes: Use the command:

     kubectl apply -f service.yaml
    
  3. Get the External IP: After applying, check the service to get the external IP address.

     kubectl get svc
    

Understanding Service Discovery

Service discovery in Kubernetes allows pods to communicate with each other without needing to know their IP addresses. This is achieved through labels and selectors. If the labels in the service do not match the labels in the pods, the service will not be able to route traffic correctly.

  1. Modify the Selector: Change the selector in the service to an incorrect label and apply the changes.

     selector:
       app: incorrect-label
    
  2. Test Access: Attempt to access the application again. You should see that the application is not accessible due to the mismatch in labels.

Load Balancing Demonstration

To demonstrate load balancing, we will use Cube Shark to visualize the traffic flow.

  1. Install Cube Shark: Follow the installation instructions from the Cube Shark documentation.

  2. Run Cube Shark: Start Cube Shark to monitor traffic.

     cubeshark tap -a
    
  3. Send Multiple Requests: Use curl to send multiple requests to the service and observe how the requests are distributed across the pods.

     for i in {1..6}; do curl -s http://<Node-IP>:30007/demo; done
    
  4. Check Cube Shark: Refresh the Cube Shark interface to see how the requests were balanced between the pods.

kubectl delete deploy <deploy-name>
kubectl delete svc <svc-name>
kubectl delete pod <pod-name>

vim Dockerfile    # add steps
docker build -t <name> .

vim deployment.yml   # add steps in yml -> (template → metadata →labels →app: sample-python-app)
kubectl apply -f deployment.yml  # create deploy

vim service.yml    # add steps in yml -> same label(deployment) -> (spec →selecter →app: sample-python-app)
kubectl apply -f service.yml  # create service
#spec -> type: LoadBalancer / NodePort

# sample-python-app(deployment.yml) = sample-python-app(deployment.yml) -> Service Discovery

kubectl get deploy  # running deploy 
kubectl get svc     #  running service 
kubectl get pods    # running pods 
kubectl get pods -o wide # running pods -> ip address
kubectl get pods -v=7  # internal communication

kubectl edit svc  / vim service.yml

template → metadata→labels →app: sample-python-app

spec → selecter →app: sample-python-app

loadBalancing

Common issues while implementing .

1/

error: externally-managed-environment

ERROR: failed to solve: process "/bin/sh -c apt-get update && apt-get install -y python3 python3-pip && pip install -r requirements.txt && cd devops" did not complete successfully: exit code: 1

Fix: setup python virtual environment in the Dockerfile. Use the updated Dockerfile below

FROM ubuntu 

WORKDIR /app 

COPY requirements.txt /app/ 

COPY devops /app/ 

RUN apt-get update && apt-get install -y python3 python3-pip python3-venv 

SHELL ["/bin/bash", "-c"] 

RUN python3 -m venv venv1 && \ 
source venv1/bin/activate && \ 
pip install --no-cache-dir -r requirements.txt 

EXPOSE 8000 

CMD source venv1/bin/activate && python3 manage.py runserver 0.0.0.0:8000

fixed code

2/

NodePort not accessible

Fix: This is because you might be running minikube on ec2 or on top of a virtualalized environment. To fix this you just need to run the

kubectl port-forward

Conclusion

In this blog post, we explored the essential functions of Kubernetes services, including load balancing, service discovery, and application exposure. We demonstrated these concepts through practical examples using a Python application and Cube Shark for traffic visualization. Understanding these concepts is crucial for any DevOps engineer working with Kubernetes, as they ensure efficient and reliable application deployment and management.