Reddit Clone Deployment with Kubernetes

Reddit Clone Deployment with Kubernetes

Scalable Deployment of Reddit Clone app from Opensource using Kubernetes & Docker. EC2|Kubernetes|Docker|CI|Git|Minikube|Kubectl

Project Overview

In this project, we'll be fetching the code of a Reddit Clone app from git repository using the CI server. And will be deploying it to a deployment server using Docker and Kubernetes.

Prerequisite

  • 2 EC2 instances out of which one will be a t2 medium and another can be t2 micro of Ubuntu AMI

  • Kubernetes should be installed in the t2 medium one for scaling

  • An account on the Docker hub for pushing the image

  • Git repository where the code exits

  • Docker should be installed in the CI server

  • Minikube

  • Kubectl

Step-1(Setting up the CI server)

After launching the EC2 instance of type t2.micro which will be primarily used for coder management and packaging we have to install Docker and clone the code from the git repository to the CI server.

Step-1.1(Docker Installation)

Before moving forward we'll be installing docker by the command:

sudo apt install docker.io

Step-1.2(Giving permission to Docker)

After the docker installation, to access docker commands we have to give user permission to the Docker using the below command.

sudo usermod -aG docker $USER && newgrp docker

Step-1.3(Cloning the code from Git)

After Docker installation, we need the project code in our local machine to proceed further with image creation. To do so we have to clone the code from the git repository below:

git clone https://github.com/LondheShubham153/reddit-clone-k8s-ingress.git

Now above you can see we have got our project directory named reddit-clone-k8s-ingress.

Step-2(Containerizing the application with Docker)

After getting the code in our Local machine we have to create the docker image of the code which will further be deployed.

Step-2.1(Writing the Docker file for containerization)

FROM node:19-alpine3.15

WORKDIR /reddit-clone

COPY . /reddit-clone
RUN npm install

EXPOSE 3000
CMD ["npm","run","dev"]

This Dockerfile creates a Docker image for a Reddit clone application using Node.js version 19 on Alpine Linux version 3.15.

The FROM instruction specifies the base image for the Docker image, which in this case is the node:19-alpine3.15 image.

The WORKDIR instruction sets the working directory for any subsequent instructions in the Dockerfile to /reddit-clone.

The COPY instruction copies the contents of the current directory (.) to the /reddit-clone directory in the Docker image.

The RUN instruction runs the npm install command to install the required dependencies for the Reddit clone application.

The EXPOSE instruction exposes port 3000 in the Docker image, which is the port used by the Reddit clone application.

The CMD instruction specifies the command to run when the Docker container is started, which in this case is the npm run dev command to start the application in development mode.

Overall, this Dockerfile sets up an environment to run a Node.js-based Reddit clone application, installs its dependencies, and starts the application in development mode on port 3000.

Step-2.2(Building the Docker image from the above Dockerfile)

After writing the Dockerfile we can build a Docker image out of it by using the command docker build . -t ritesh1999/reddit-clone . this command builds a Docker image for the Reddit clone application based on the Dockerfile in the current directory and tags it with the name ritesh1999/reddit-clone:

Now above you can see an image 48ba72a7cd20 has been created and tagged. Using docker images you can see the image that has been created below:

Step-2.3(Logging in to Docker Hub)

Docker Hub is nothing but a hub of repositories containing docker Images. Once the image is built from the docker file, we have to push the image to the Docker hub so that during the deployment the image can be fetched from DockerHub itself. It works like GitHub.

So, to push the image we have to log in to our docker hub account from the CLI using the command: docker login followed by the username and password of your docker account.

Step-2.4(Pushing the image to Docker Hub)

Once the login is successful we can push the image by using the command below where docker push username/tagname:latest is the syntax:

 docker push ritesh1999/reddit-clone:latest

Now from the above image from Docker Hub, you can see that the image has been pushed.

Step-3(Setting up Deployment Server)

To set up the deployment server we have to install all the prerequisites as listed above in the prerequisite section.

As this is the Deployment server we need Kubernetes to be installed. We will be using Minikube to create a Kubernetes cluster.

And to support Minikube we also need Docker to be installed.

NB: Minikube is a lightweight Kubernetes implementation that creates a VM on your local machine and deploys a simple cluster containing only one node.

Step-3.1(Docker and Minikube Installation)

Using sudo apt install docker.io we can install docker exactly as we did for CI server.

And give the permission using sudo usermod -aG docker $USER && newgrp docker

And below is the commands for Minikube and Kubernetes cluster setup.

curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube 

sudo snap install kubectl --classic
minikube start --driver=docker

These commands are used to set up a Kubernetes development environment using Minikube with the Docker driver.

  • The first command curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 downloads the latest version of Minikube for Linux in the current directory using the curl command.

  • The second command sudo install minikube-linux-amd64 /usr/local/bin/minikube installs the downloaded Minikube binary to /usr/local/bin/minikube which makes it accessible from anywhere in the terminal.

  • The third command sudo snap install kubectl --classic installs the kubectl command-line tool using the Snap package manager.

  • Finally, the fourth command minikube start --driver=docker starts the Minikube cluster with the Docker driver. The --driver=docker flag specifies that the Docker driver should be used as the runtime for the Kubernetes nodes in the Minikube cluster.

Overall, these commands set up a local Kubernetes cluster using Minikube with the Docker driver and install the necessary command-line tools such as kubectl to interact with the cluster.

With this, the setup has been completed.

Step-4(App Deployment Preparation)

Step-4.1(Writing the deployment.yaml File)

By creating and applying a deployment.yaml file, Kubernetes will create a Deployment object based on the specified configuration and ensure that the desired state of the Deployment is maintained, handling tasks such as scaling and rolling updates automatically.

So, for our application the deployment file will be as below:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: reddit-clone-deployment
  labels:
    app: reddit-clone
spec:
  replicas: 3
  selector:
    matchLabels:
      app: reddit-clone
  template:
    metadata:
      labels:
        app: reddit-clone
    spec:
      containers:
      - name: reddit-clone
        image: ritesh1999/reddit-clone
        ports:
        - containerPort: 3000

Step-4.2(Deployment.yaml explanation)

This is an example Kubernetes Deployment configuration file (deployment.yaml) for deploying the Reddit clone application using the image ritesh1999/reddit-clone.

The file starts with the apiVersion and kind fields, which define the Kubernetes API version and object type respectively. In this case, the object type is Deployment and the API version is apps/v1.

The metadata field includes the name and labels for the Deployment object. The name field specifies the name of the Deployment object as reddit-clone-deployment, and the labels field includes a label app: reddit-clone.

The spec field includes the specifications for the Deployment. The replicas field specifies that two replicas of the pod should be created and managed by the Deployment. The selector field specifies the label selector that identifies the set of pods managed by the Deployment. In this case, the selector matches the app: reddit-clone label.

The template field includes the specifications for the pod template that defines the characteristics of the pod. The metadata field includes the labels for the pod. The spec field includes the specifications for the container that runs in the pod. In this case, there is only one container named reddit-clone, which uses the ritesh1999/reddit-clone image and exposes port 3000.

Overall, this configuration file defines a Kubernetes Deployment for the Reddit clone application with two replicas, using the ritesh1999/reddit-clone image and exposing port 3000.

Step-4.3(Applying the deployment.yaml)

After writing the deployment.yaml configuration we have to apply the configuration to complete the deployment.

kubectl apply -f deployment.yaml

The kubectl apply -f deployment.yaml command applies the Kubernetes Deployment configuration specified in the deployment.yaml file.

When you run this command, Kubernetes reads the deployment.yaml file and creates a new Deployment object or updates an existing one, based on the information provided in the file.

After running kubectl apply -f deployment.yaml, you can use kubectl get deployments to verify that the Deployment has been created or updated successfully as shown below in which we can see there are 3 Pods available because we have defined 3 as Replicas:

Step-4.4(Writing Service.yaml)

Currently, our Reddit Clone application is running inside the Pods or the container of the Kubernetes Cluster that's why it is not yet accessible to the outside world. This service.yaml file will help to expose and IP of the Cluster to the outside and will make is accessible for us.

apiVersion: v1
kind: Service
metadata:
  name: reddit-clone-service
  labels:
    app: reddit-clone
spec:
  type: NodePort
  ports:
  - port: 3000
    targetPort: 3000
    nodePort: 31000
  selector:
    app: reddit-clone

Step-4.5(service.yaml explanation)

The file starts with the apiVersion and kind fields, which define the Kubernetes API version and object type respectively. In this case, the object type is Service and the API version is v1.

The metadata field includes the name and labels for the Service object. The name field specifies the name of the Service object as reddit-clone-service, and the labels field includes a label app: reddit-clone.

The spec field includes the specifications for the Service. The type field specifies the type of the Service as NodePort, which exposes the Service on a static port on each node in the cluster.

The ports field includes the port mappings for the Service. In this case, the Service is exposed on port 3000, which is the port on which the Reddit clone application is running in the container. The targetPort field specifies the port on which the application is listening inside the container, which is also set to 3000. The nodePort field specifies the port on which the Service is exposed on each node in the cluster. In this case, it is set to 31000.

The selector field specifies the label selector that identifies the set of pods that the Service should route traffic to. In this case, the selector matches the app: reddit-clone label.

Overall, this configuration file defines a Kubernetes Service for the Reddit clone application using a NodePort service type, exposing the Service on port 31000 on each node in the cluster and routing traffic to the pods with the app: reddit-clone label.

Step-4.6(Applying service.yaml)

kubectl apply -f Service.yaml

When you run this command, Kubernetes reads the Service.yaml file and creates a new Service object or updates an existing one, based on the information provided in the file.

After applying the Service.yaml configuration we can see the app is deployed using the command:

minikube service reddit-clone-service

Here reddit-clone-service is the service name. This command also gives us an URL to access the application locally which is http://192.168.49.2:31000

NB: However, this URL is not yet accessible outside.

Step-5(Exposing the Application)

Step-5.1(Exposing the Deployment)

kubectl expose deployment reddit-clone-deployment --type=NodePort

The kubectl expose deployment reddit-clone-deployment --type=NodePort command creates a new Kubernetes Service object to expose the deployment named reddit-clone-deployment using the NodePort service type.

When you run this command, Kubernetes creates a new Service object and sets its selector to match the labels on the Pods managed by the reddit-clone-deployment. It also sets the Service's type to NodePort, which exposes the Service on a static port on each node in the cluster.

Step-5.2(Exposing the Service)

kubectl port-forward svc/reddit-clone-service 3000:3000 --address 0.0.0.0 &

In the above step we have just exposed the deployment now we'll be exposing the Service using the Port Forwarding method.

The kubectl port-forward svc/reddit-clone-service 3000:3000 --address 0.0.0.0 & command creates a port forwarding tunnel between your local machine and the Kubernetes Service named reddit-clone-service.

When you run this command, Kubernetes listens on port 3000 of your local machine and forwards any traffic received on that port to port 3000 of the reddit-clone-service in the Kubernetes cluster. The --address flag specifies that the tunnel should be accessible from any IP address (0.0.0.0).

NB: Note that this command runs in the foreground, so you will need to keep the terminal window open for as long as you want the port forwarding tunnel to remain active. If you want to run the command in the background, you can remove the & at the end of the command.

Step-5.3(Exposing the IP of EC2 instance)

As you can see above the port has been forwarded to 3000. However, this is still not accessible from Browser externally. To access this we need to edit the inbound rule of our Deployment Server. Here we have to add port 3000 and give it IvP4-Everywhere permission as below:

Application Deployed

After completing the above steps the Reddit clone app is finally deployed and now accessible from outside: