Deploying a Reddit Clone with Ingress in Kubernetes using Minikube

Deploying a Reddit Clone with Ingress in Kubernetes using Minikube

Hands-On Kubernetes: Mastering Ingress with a Reddit Clone Deployment in Minikube

Welcome back, fellow Kubernetes explorers! In our previous blog, we took you on a journey to set up Minikube on your Linux machine. If you haven't already installed Minikube, make sure to check out our guide here as it's the first step toward today's exciting adventure.

We're diving deeper into the Kubernetes universe in this hands-on project guide. But, before we begin this exciting Reddit clone deployment journey, let's make sure you have the following prerequisites:

Prerequisites:

  • Basic Knowledge of Kubernetes: This adventure assumes that you have a basic understanding of Kubernetes objects such as Pod, Deployment, Service, and Ingress.

  • DockerHub Account: This blog requires an active DockerHub account that will be used to upload and download the docker image we will be building. You can create an account by visiting https://hub.docker.com/

  • Git: Git installed on your Ubuntu machine

  • Docker & Minikube Installed: If you haven't already set up docker & Minikube cluster, please refer to our installation guide here to get started.

With all the prerequisites satisfied, let’s dive into our project!

Step 1: Clone the source code of the project

Run the given command in your Linux terminal to download the project files

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

Since the project is evolving continuously, we will be using the branch blog for the purpose of this guide. Let’s checkout into the blog branch using the command: git checkout blog

Step 2: Build the Dockerfile

The project folder includes a Dockerfile that will be used to build the image.

Dockerfile:

FROM node:19-alpine3.15

WORKDIR /reddit-clone

COPY . /reddit-clone
RUN npm install 

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

Run the below-given commands inside the root of the project folder to build the docker image, replace the placeholder <username> with your DockerHub username.

docker build . -t <username>/reddit-clone:latest

Use the command docker images to view your newly built image, the output should be similar to this:

Step 3: Push the docker image to Docker Hub

After building the image, we need to push it to docker hub, our Kubernetes deployment will later fetch the same image from docker hub to run the app.

Login to DockerHub from docker CLI:

This step is crucial to push docker images. Run the given command to log in to docker hub with your username and password. docker login

Push the Docker image to DockerHub:

Use the command docker push <username>/reddit-clone:latest to push the image, replace the placeholder <username> with your username.

After pushing the image, refresh your DockerHub website, and you will be able to see a new repository has been created containing your docker image.

Step 4: Creating a Deployment Manifest for K8s

Congrats on reaching here! 🥳 You have now successfully built a docker image and uploaded it to Docker Hub, thus completing the basic steps of the continuous integration Process.

Now we will be focusing on deploying the docker image in a K8s cluster. For this, we will be using the Deployment object of K8s to create Pods that run our image.

What is a Deployment?

In K8s, a Deployment object acts like the manager of the Pods, It ensures that the specified number of pod replicas with the desired container images are running normally. If a pod encounters problems or needs an update, the Deployment handles it seamlessly while maintaining the desired number of pods. K8s objects are declared using YAML files and are often referred to as manifests. You can read more about the Deployment object here.

You can view the deployment.yml file present in the project folder or copy it from here.

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: <username>/reddit-clone:latest
        ports:
        - containerPort: 3000

Make sure to replace the value of image key with that of your image name as shown in the YAML file.

The deployment creates 2 pods running 1 container each with the reddit-clone image we pushed earlier. The key containerPort declares that the container accepts connections from port 3000.

Run kubectl apply -f deployment.yml to create the deployment object in K8s. You should see an output similar to this:

Run kubectl get deployment and kubectl get pods to ensure that your deployment has been successfully created and pods are running. Your output should look like this:

Step 5: Create a Service Manifest for K8s

Our next step is to create a service object that will allow us to connect to the pods created by the deployment file.

A Service in K8s serves as a link between distinct pods or microservices inside a cluster. Consider it a well-known phone number in a directory that enables pods to connect and converse despite their dynamic nature or changing IP addresses. Services are critical because they provide a consistent and discoverable endpoint for applications, as well as load balancing and abstraction of underlying pod modifications. The dynamic and scalable nature of Kubernetes would make it difficult for pods to identify and interact with one another without Services. You can read more about Service Objects here.

You can view the service.yml file present in the project folder or copy the one below and paste it into your YAML file

apiVersion: v1
# Indicates this as a service
kind: Service
metadata:
  # Service name
  name: reddit-clone-service
spec:
  selector:
    # Selector for Pods
    app: reddit-clone
  ports:
    # Port is the port service is gonna listen to
  - port: 3000
    # Target port is the port container is listening to
    targetPort: 3000
    protocol: TCP
  # We are using ClusterIP service which is not directly
  # accessible from outside the cluster, other types of services
  # are NodePort, LoadBalancer
  type: ClusterIP

Run kubectl apply -f service.yml to create this service in K8s. Run kubectl get svc to check if the service has been created, the output should look like this:

Step 6: Test your application

Now it is time to test our deployed application. Since our service object is of the type ClusterIP, it is not accessible outside the cluster, but for the purpose of testing, we can forward all requests received in a specific port on the host to the service port using kubectl port-forward command.

Make sure port 3000 is not blocked by a firewall or a security group if you are running Linux on the cloud, This is crucial for testing the app.

You need to note the IP of the machine Minikube is running in, use ifconfig command on Linux to find your machine’s IP address.

Run the command kubectl port-forward svc/reddit-clone-service 3000:3000 --address 0.0.0.0 After running this command, keep the terminal open.

Now in your browser, open the URL <LinuxIP>:3000 Replace the placeholder <LinuxIP> with the IP of the Linux machine you noted above. If everything is configured well, you should see a site similar to this:

and in your terminal running the port-forward command, the output should look something like this:

The app has now been successfully deployed! Congratulations on reaching this far! 🥳

Now we will be configuring ingress.

Step 7: Configuring Ingress

Ingress is a clever traffic management and routing solution for Kubernetes apps running within the cluster. While LoadBalancer and NodePort Services are useful for exposing specific services, Ingress offers a more advanced solution. It serves as a single entry point for various services, making it an excellent solution when you need to access numerous microservices via distinct URLs or domains. You can read more about ingress and ingress controllers here

1. Enable Ingress in Minikube

In Minikube, ingress comes as an addon and we need to enable it before configuring it. Run minikube addons enable ingress in the terminal to enable ingress. The output should be like this:

2. Write the Ingress K8s Manifest

You can use the ingress.yml present in the project folder or copy the YAML from here:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-reddit-app
spec:
  ingressClassName: nginx
  rules:
  - host: redditclone.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: reddit-clone-service
            # Port Service is listening on
            port:
              number: 3000
  - host: "*.redditclone.com"
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: reddit-clone-service
            # Port Service is listening on
            port:
              number: 3000

We have used the domain redditclone.com as our entry point to the ingress Create the ingress rule using the command kubectl apply -f ingress.yml

and then run kubectl get ingress, the output should be like this:

We need to wait for the Address column to be populated, it will take some time before it is so keep checking kubectl get ingress.

After the address column is populated like this

Note down the IP displayed in the address column.

3. Test the Ingress

We have now successfully deployed the ingress and now we can test it. To test the ingress, we need to send a request to redditclone.com , however, we don’t own this domain, and there’s no DNS record pointing redditclone.com to our cluster. So, we will be using curl command to forcefully resolve redditclone.com to the IP of ingress as noted above. The command is:

curl --resolve "redditclone.com:80:<IP of Ingress>" redditclone.com

Upon executing this command, we immediately get a rather big output of the HTML file which is of our Reddit clone.

NOTE: If you are running minikube in a linux machine with GUI and want to access redditclone.com from your browser, you can edit /etc/hosts file using vi to add a line with the format like: <IP of Ingress> redditclone.com The file should then look something like this:

After saving the file, you should be able to access the app by using URL redditclone.com in your browser.

Well Done on Your Reddit Clone Deployment! 🔥

Congratulations on successfully deploying the Reddit clone app with Minikube! You've unlocked the door to the Kubernetes world, and this is just the beginning. Keep exploring, learning, and building with Kubernetes—it's a journey filled with endless possibilities.

If you run into issues while deploying this app or have some suggestions on improving the blog or just want to reach out to showcase your deployment, please contact me on LinkedIn.

Thank you fellow K8s adventurers, Do follow me for more such exciting blogs on K8s, Docker, and Linux. 🧑🏻‍💻