Deploying a Reddit Clone App on Kubernetes with Docker, CI/CD, and Ingress

In this project, we'll explore the process of deploying a Reddit Clone application on a Kubernetes cluster using Docker, CI/CD, and Ingress. We started by setting up an EC2 instance and cloning the Reddit source code onto it. After installing Docker on the instance, we proceeded to containerize the application using a Dockerfile. The Dockerfile defined a Node.js environment, installed dependencies, and exposed port 3000. Next, we built a Docker image for the application and pushed it to Docker Hub, making it accessible during deployment. Moving on, we logged into our deployment server, an EC2 instance where we installed Minikube. To deploy the application, we created a deployment.yaml file specifying the desired configuration and applied it using the kubectl command. We verified the successful creation of the deployment and then wrote a service.yaml file to expose the application to the outside world. After applying the service configuration, we obtained an accessible URL for our application. Finally, we tested the ingress functionality to ensure traffic routing to the Kubernetes cluster services.

Table of Contents:

  1. Introduction

  2. Setting up the CI Server
    2.1. Launching an EC2 T2 Micro Instance
    2.2. Cloning the Reddit Source Code and Installing Docker

  3. Containerizing the Application with Docker
    3.1. Creating a Dockerfile
    3.2. Building the Docker Image

  4. Pushing the Image to Docker Hub
    4.1. Logging into Docker Hub
    4.2. Pushing the Docker Image

  5. Setting up the Deployment Server
    5.1. Launching an EC2 Medium Instance and Installing Minikube

  6. Creating the Deployment Configuration
    6.1. Writing deployment.yaml
    6.2. Applying the Deployment Configuration

  7. Creating the Service Configuration
    7.1. Writing service.yaml
    7.2. Applying the Service Configuration

  8. Exposing the Application
    8.1. Using Port Forwarding for Local Access
    8.2. Allowing External Access through Inbound Rule Configuration

  9. Testing the Deployed Application

  10. Enabling Ingress and Testing
    10.1. Applying the Ingress Configuration
    10.2. Testing the Application using Curl

  11. Conclusion

Step 1 — Clone the Source Code, Containerize the application using Docker, Building Docker Image, and Push the Image to Docker Hub on your CI Server (T2 Micro Instance)

Step 2— Write a Kubernetes Manifest File (Deployment.yml and Service.yml) on your CD Server (T2 Medium Instance)

Step 3— Deploy the app to Kubernetes using Deployment.yml

Step 4 — Create a Service.yml

Step 5— Expose the app and test it. Configure ingress.yml

NOW, LET’S GET STARTED WITH DEEPER DIVE INTO ALL OF THESE STEPS

Here are two instances:

Login into your CI Server Ec2 instance:

First — Set up an EC2 T2 micro instance and clone the Reddit source code on your EC2 Instance. Use an Ubuntu image with a key-pair, and enable HTTP and HTTPS traffic. Install docker on this EC2 Instance.

The bellow command needs to install for the CI server

sudo apt-get update
sudo apt-get install docker.io -y
sudo usermod -aG docker $USER && newgrp docker
git clone https://github.com/nahidkishore/reddit-clone-k8s-ingress.git
cd reddit-clone-k8s-ingress
docker login (Enter your docker hub Username and Password)
docker build . -t nahid0002/reddit-clone
docker push nahid0002/reddit-clone

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/nahidkishore/reddit-clone-k8s-ingress.git

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

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.

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.

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 reddit-clone:latest

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 reddit-clone:latest

Login into the docker repo

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.

Pushing the image to Docker Hub

Once the login is successful we can push the image by using the command below where docker push nahid0002/reddit-clone:latest is the syntax:

docker push nahid0002/reddit-clone:latest

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

Login into your Deployment Server:

We will launch an EC2 Medium Instance (2vCPU) and install Minikube on it. To install Minikube, Docker is a prerequisite.

The bellow command needs to install for the Deployment server

sudo apt-get update
sudo apt-get install docker.io -y
sudo usermod -aG docker $USER && newgrp docker
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
mkdir k8s
cd k8s/

Create Deployment.yml

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: 2
  selector:
    matchLabels:
      app: reddit-clone
  template:
    metadata:
      labels:
        app: reddit-clone
    spec:
      containers:
      - name: reddit-clone
        image: nahid0002/reddit-clone
        ports:
        - containerPort: 3000

Apply the deployment file:

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

kubectl apply -f deployment.yaml
kubectl get deployment

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 2 Pods available because we have defined 2 as Replicas:

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

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.

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
or
minikube service reddit-clone-service --url

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

Exposing the Application

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.

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.

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

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:

Test Ingress

Now It's time to test your ingress so use the curl -L domain/test command in the terminal.

Ingress defines a set of rules that allows the inbound connection to access Kubernetes cluster services. Ingress is used to route external traffic to the Kubernetes endpoints by different URLs. We will need to enable ingress on our Minikube

minikube addons enable ingress

Write an Ingress File

vim Ingress.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-reddit-app
spec:
  rules:
  - host: "domain.com"
    http:
      paths:
      - pathType: Prefix
        path: "/test"
        backend:
          service:
            name: reddit-clone-service
            port:
              number: 3000
  - host: "*.domain.com"
    http:
      paths:
      - pathType: Prefix
        path: "/test"
        backend:
          service:
            name: reddit-clone-service
            port:
              number: 3000

You can apply the Ingress file using the below command and finally check whether the application is working or not by using the curl command with the specified domain name.

kubectl apply -f ingress.yml
curl -L domain.com/test

In this project, we successfully deployed a Reddit clone application using Docker and Kubernetes. By containerizing the application and leveraging the power of Kubernetes, we achieved efficient deployment, scaling, and management of our application. Through the use of deployment and service configurations, we were able to maintain the desired state of the application and expose it to external traffic. The integration of Docker Hub allowed for easy access to the Docker image during deployment. We also explored the capabilities of ingress in routing inbound connections to the Kubernetes cluster services. Overall, this project demonstrates the seamless combination of containerization, orchestration, and service exposure provided by Docker and Kubernetes, enabling smooth and scalable deployment of applications.

Ingress and Ingress Controllers are essential tools for managing external access to services in Kubernetes. They provide a flexible and powerful way to route HTTP and HTTPS traffic to your applications, making it easier to manage and scale your containerized workloads.

Thank you for reading this blog. If you found this blog helpful, please like, share, and follow me for more blog posts like this in the future.

— Happy Learning !!!

Let’s connect !!!

Linkedin

HashNode

Medium

Github

Mail