Kubernetes Deployment: Connect Your Front End to Your Back End With Nginx

Deploy a full-stack application with Kubernetes

Vidhyanshu Jain
Better Programming

--

Photo by Joseph Barrientos on Unsplash

Kubernetes is one of the best orchestration tools available. Furthermore, it is backed by Google, so we don’t have any doubts regarding the support and performance that Kubernetes can provide.

In this article, we will be using Minikube to understand how to deploy a full-stack application in Kubernetes.

I remember that while I was working on my first Kubernetes deployment, I realized that deploying a Kubernetes full-stack application and connecting the front end and back end can be a bit tricky. So I decided to write a tutorial that will help you deploy your full-stack application.

Prerequisites

This tutorial assumes that you have a basic understanding of Kubernetes. To keep this tutorial relevant to the topic, it’s highly recommended that you should at least read these topics.

Also, if you are working on your local machine, please install minikube, kubectl, and docker.

What Are We Going to Deploy Today?

The most common type of full-stack application has at least three components:

  • Database
  • API server
  • Front-end application

This tutorial aims to help you get familiar with Kubernetes deployment. Once you understand how to deploy the above three components, you’ll be able to deploy any application in Kubernetes.

We will be using Node.js for the back end and MongoDB for the database, and to keep it straightforward, we will use a simple HTML file with Ajax for the front end. You can select React or Angular or any front-end framework of your choice. The choice of your framework does not affect any of the steps.

Step by step, we will visit all three components. You can find all the code related to this article on Github.

Let’s dive straight into it then.

Back End

For this tutorial, we will keep our back end very simple. We have a simple Node server with Express and Mongoose.

We are using Mongoose to connect to our MongoDB. And I have chosen the port 3000 for Express.

Note: We have used mongo-service as the hostname for database URL. That’s because Kubernetes provides you with abstractions called services. We will create a mongo-service service in the latter part of this tutorial. And you can use the service name as the hostname to connect to your application (mongo-service, in this case).

TLDR; If you have a Kubernetes service named mongo-service, you can use mongo-service as the DNS name of your application. It’s the responsibility of Kubernetes to forward the request to the corresponding pod. Don’t worry, we will revisit this.

We should also add a route /api to our back-end application.

That’s it. We are now done with our front-end application. All we have to do now is to containerize the application and write Kubernetes Objects.

Containerizing Node app

To deploy an application to Kubernetes, we need a Docker image of that application. So in this step, we will containerize our back-end app. Below is a fairly simple Dockerfile for our Node app.

I have used node-alpine as my base image. To create the Docker image, run the following command:

docker build -t backend .

Now we have an image called backend. Next, we will write Kubernetes objects.

Kubernetes objects for Node app

For any Kubernetes deployment, we need Kubernetes objects. These Kubernetes objects represent the state of your container.

We will create a Kubernetes deployment object. Deployment objects contain information such as the Docker image used, the number of replica sets, resource allocation, etc.

We will create a deployment called node-deployment. We will use our back-end image and create one replica of the container. Inside the node-deployment.yaml file, write:

With this deployment object, we are telling Kubernetes to create a deployment with name node-deployment which has one replica set of pod named node-pod. node-pod is a container of backend image with the concerned container port 3000.

To create this deployment, just run the following command:

kubectl apply -f node-deployment.yaml

We have created a deployment, but we have no way of communicating with it. To solve this problem, we will have to create a service. Service is an abstraction in Kubernetes that assigns IP addresses to pods and a single DNS to a set of pods. As we have seen before while connecting to MongoDB, we used mongo-service as the hostname. We will be writing a service called node-service so that we can connect to our back-end app from the front end.

Our node-service.yaml file looks like this:

We have now created a service of type LoadBalancer. This service is bound to all the replicas of the pod with the name node-pod. And you can now talk to the node server using the hostname node-pod.

Apply the service using the following command:

kubectl apply -f node-service.yaml

This concludes our back-end step. We can now start working on our front-end app.

Front End

For the front end, I am using a simple HTML file with jQuery just to keep this tutorial straightforward. But you can use any front-end framework of your choice. Whichever framework you use will not affect these steps.

To serve our front-end application, we will be using the Nginx web server. The reason we are using the Nginx server is that it provides a proxy. And we will be needing Nginx proxy to pass our request to our node deployment.

We will create a very simple HTML file named index.html. And we will use Ajax to query our node server.

From the web browser, if you try to connect to http://node-server:3000/api, you will get the “host not found” error. This is because the DNS node-server is not registered on the internet.

A workaround for this is to send the request to the front-end application, let’s say to a path /api. And using Nginx, we can forward the query to our back-end application.

What I mean by that is that we will send all of our back-end calls to the /apipath in our front-end application and configure Nginx such that it will pass the request to http://node-service/api.

Our index.html file looks like this:

See how we have used /api as our URL?

const url = "/api/"

Now we will write the Nginx conf Nginx.conf file to forward the request from the path /api to http://node-service/api.

Our Nginx.conf file should look like this:

This config file tells Nginx that for all the requests for path /api, send the request to http://node-service:3000/api. You can read more about proxy_pass in the documentation.

Containerizing the front end

Next, we will containerize the application for Kubernetes deployment. In our front-end image, we need to replace the default Nginx conf file with our conf file.

Our Dockerfile will look like this:

Line 4 removes the default Nginx conf file from the image

Line 5 copies our new config file to Conf.d folder.

With this, we have now successfully created our Docker image for the front-end app. Let’s move on to the next step and create Kubernetes deployment and service for our front-end app.

Kubernetes objects for the front end

The deployment object for Nginx will be very similar to the deployment object we created in our back-end app.

After running kubectl apply, we have a deployment named frontend-deployment, which has one replica of a pod named frontend-pod that is made using the frontend image.

Similarly, our nginx-service.yaml file should look like this:

This creates a service with the name frontend-service of the LoadBalancer type, which is bound to all the replicas of the pod with the name frontend-pod.

This concludes our front-end step. Now we can proceed to our last step, which is the database.

Database

Deploying our database in Kubernetes is the easiest step because we don’t have to create any Docker image for it. And it’s very easy to configure.

We don’t need to create a MongoDB image because we can directly use the MongoDB image from Docker Hub. We can directly start writing our deployment object.

This creates a simple Mongo deployment. The env key inside the container tells Kubernetes that these are the environment values with which you have to create the image. We are basically telling Kubernetes to create a deployment with one replica set of pod, mongo-pod, which has a Mongo container and the name of the database is database.

For the final step, we will write our mongo-service.

After the kubectl apply command, we should have created a service named mongo-service that’s bound to all the replicas with the name mongo-pad. And you can now talk to MongoDB using the hostname mongo-pod.

Conclusion

With this, we have deployed our full-stack applications in Kubernetes.

Using the Nginx proxy_pass derivative, we were able to connect our front-end deployment to our back-end deployment. Most people face issues when they have to connect the front end and back end in Kubernetes.

Now you can deploy a complete full-stack application by following the above steps.

Happy coding.

--

--