How to Build and Deploy a React.js with a Node.js Dockerized Containers to a Kubernetes Cluster
Tags: kubernetes, node, react, docker
Published: 2023-05-17 14:56:02

This tutorial guides you on how to build and Dockerize a React.js and a Node.js application. It also teaches you how to deploy the two Dockerized applications to a Kubernetes Cluster.

[React.js](https://reactjs.org/) is an open-source Javascript framework for building single-page web applications and interactive user interfaces. You can use a few lines of code to create a React.js application. [Node.js](https://nodejs.org/) is an open-source Javascript runtime framework for building scalable network applications.

In this tutorial, you will use the Node.js framework to create an [Express](https://expressjs.com/) back-end server. You will use React.js to create a front-end web application and connect the two applications. The React.js application will make API calls to the Express server.

After creating the Node.js Express server and React.js web application, you will use Docker to containerize the two applications. Docker allows us to run the applications as stand-alone containers. Each container will have all the libraries, code, and packages needed to run an application. You will finally deploy the two containerized applications to the Kubernetes Cluster.

### Prerequisites
To follow along easily and implement the concepts in this tutorial, you need to be familiar with [React.js](https://reactjs.org/), [Node.js](https://nodejs.org/), and [Docker](https://docs.docker.com/get-docker/). You will need the following already setup on your computer:

- [VS Code](https://code.visualstudio.com/Download) text editor.
- [Node.js](https://nodejs.org/)
- [Docker Desktop](https://www.docker.com/products/docker-desktop) installed onto your machine

### What is Kubernetes?
Kubernetes is open-source software that assists in container orchestration. Kubernetes automates the deployment and management of multiple containerized applications in a Kubernetes cluster. You can create a Kubernetes Cluster on cloud-based service providers such as [AWS](https://aws.amazon.com/eks/), [Microsoft Azure](https://azure.microsoft.com/en-us/products/kubernetes-service/), and [Google Cloud](https://cloud.google.com/kubernetes-engine). You can also create a Kubernetes cluster on your local machine using [Minikube](https://minikube.sigs.k8s.io/docs/start/). 

The cloud-based service providers are best suited for large applications that require powerful computing resources. These providers are also best when running applications in production.

Minikube allows us to create and run a Kubernetes Cluster on your local machine. It is best suited for testing simple and small applications. Most applications that run on the Minikube require little computing resources. For this tutorial, you will deploy the two Docker containers to a Minikube Kubernetes Cluster. Let's start working on the two applications.

### Creating the Node.js Application
To create the Node.js application, follow the steps below:

Step 1: Create a project working directory named `react-node-app` and open it with VS Code. 
In the project working directory, create a new folder named `backend` and `cd` into the created folder. This folder will contain all the code and dependencies for the Express server. 

Step 2: Initialize the Node.js application as follows:

```npm
npm init --y
```
The command will initialize the Node.js application and generate the `package.json` file. Next, let's install all the dependencies required to run the Node.js application:

```npm
npm i express
npm i -g nodemon
```
The command will install `express` and `nodemon`. You will use the `express` to create the back-end server. 

You will use `nodemon` to monitor the Node.js application scripts and detect any changes. When any changes are detected, it automatically restarts the Node.js application during development.

Step 3: Next, open the `package.json` and the following script for `nodemon` to become effective:

```npm
"dev": "nodemon -L app.js"
```
Step 4: In the `backend` folder, create a new file named `app.js`

Step 5: Add the following code in the `app.js`:

```node
const express = require('express')
const cors = require('cors')

const app = express()

app.use(cors())

app.get('/', (req, res) => {
  res.json([
    {
      "id":"1",
      "title":"Movie Review: The Perk of Being a Wallflower"
    },
    {
      "id":"2",
      "title":"Game Review: Need for Speed"
    },
    {
      "id":"3",
      "title":"Show Review: Looking for Alaska"
    }
  ])
})

app.listen(4000, () => {
  console.log('listening for requests on port 4000')
})
```
The code above will create an Express `get` route. The back-end will be listening for requests on port 4000. Let's run the Node.js application.

#### Running the Node.js Application
To run the Node.js application, use the following command:

```npm
npm run dev
```
The command will start our application as shown below:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ruveveg1u7dnv8sujn4t.png)
We can access the Node.js application on `http://localhost:4000/` as shown below:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/afhsxmgyi5ery7mmhs2h.png)

### Creating the React.js Application
To create the React.js application, apply the following steps below:

Step 1: While in the project working directory, run the following command to create a React.js application

```npm
npx create-react-app frontend
```
The command will create a new folder named `frontend` in the project working directory. Now, `cd` into the `frontend` folder.

Step 2: Go to the `frontend` folder, and open the `src` folder as shown below:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sw9juhjtb2skpifonqyy.png)

Step 3: In the `src` folder, open the `App.js` file, delete everything from it and paste the following code:

```react
import { useEffect, useState } from 'react'
import './App.css';

function App() {
  const [blogs, setBlogs] = useState([])
  useEffect(() => {
    fetch('http://localhost:4000/')
      .then(res => res.json())
      .then(data => setBlogs(data))
  }, [])

  return (
    <div className="App">
      <header className="App-header">
        <h1>all blogs</h1>
        {blogs && blogs.map(blog => (
          <div key={blog.id}>{blog.title}</div>
        ))}
      </header>
    </div>
  );
}

export default App;
```
The code will create a simple react application that will make API requests to the Express server. It will fetch the results from http://localhost:4000/ where our back-end is running.

#### Running the React.js Application
Before you run the React.js application, ensure the Node.js application is running on http://localhost:4000/. To run the React.js application, run the following code:

```npm
npm start
```
The command will start our application. You can access it on http://localhost:3000/ as shown below:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z4yh0e00yvc6rrw5jkgk.png)

You have connected the two applications, and the front-end can now communicate with the back-end. Let's now containerize the two applications using Docker.

### Containerizing the Node.js Application
To containerize the Node.js using Docker, follow the steps below:

Step 1: Create a file named `Dockerfile` in the `backend` folder
The `Dockerfile` will have the commands required to build a Docker image for the Node.js application. Add the following code in the created `Dockefile`:

```docker
# Requires node:18-alpine as the base image for Dockerizing the Node.js application
FROM node:18-alpine

# It installs the nodemon package for monitoring the Express server
RUN npm install -g nodemon

# Creating the working directory
WORKDIR /app

# Copying the dependencies in the package.json file
COPY package.json .

#Installing all the dependencies
RUN npm install

#Copying all the files to the working directory
COPY . .

#Container will run on this port
EXPOSE 4000

#Command to start the Docker container Node.js application
CMD ["npm", "run", "dev"]
```
Step 2: Building the Docker image
To build the Docker image for the Node.js application, first `cd` into the `backend` folder. You will then run the following command:

```docker
docker build -t bravinwasike/node-js .
```
The command will build the Docker image and give the following output in your terminal:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1hiiqidkopcnk5iknljx.png)

#### Pushing the Node.js Docker Image to Docker Hub
To push the Docker image to Docker Hub, run the following command:

```docker
docker push bravinwasike/node-js
```
#### Starting the Containerized Node.js Application
To start the containerized Node.js application, run the following command:

```docker
docker run -p 4000:4000 bravinwasike/node-js
```
The command will start the containerized Node.js application as shown below:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nzy3lpk4335dgd3s9uwk.png)

You can also access the containerized Node.js application on `http://localhost:4000/` as shown below:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lzoklvqmjk48hqgqvuna.png)

### Containerizing the React.js Application
To containerize the React.js using Docker, follow the steps below:

Step 1: Create a file `Dockerfile` in the `frontend` folder and add the following code in the created Dockefile:

```docker
FROM node:18-alpine

WORKDIR /app

COPY package.json .

RUN npm install

COPY . .

EXPOSE 3000

CMD ["npm", "start"]
```
Step 2: Building the Docker image
To build the Docker image for the React.js application, first `cd` into the `frontend` folder. You will then run the following command:

```docker
docker build -t bravinwasike/react-js .
```
The command will build the Docker image and give the following output in your terminal:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dlbf04zov6nni7zdkv5o.png)

#### Pushing the React.js Docker Image to Docker Hub
To push the Docker image to Docker Hub, run the following command:

```docker
docker push bravinwasike/react-js
```
#### Starting the Containerized React.js Application
Before you run the containerized React.js application, ensure the containerized Node.js application is running on http://localhost:4000/. To start the containerized React.js application, run the following command:

```docker
docker run -p 3000:3000 bravinwasike/react-js
```
The command will start the containerized React.js application. We can also access the containerized React.js application on `http://localhost:3000/` as shown below:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g2eabxrsjlddjoxqb49y.png)

Our containerized React.js application is also running and connected to the back-end. Let's now deploy the two containerized applications to the Kubernetes Cluster.

### Creating the Kubernetes Cluster
In this tutorial, you will create and run Kubernetes Cluster locally using Minikube. You will deploy the two containerized applications to the Minikube Kubernetes Cluster. Minikube comes together with Docker during the installation process. To check the installed Minikube version, run the following command:

```minikube
minikube version
```
Minikube depends on the Docker driver to run. To create and run a Kubernetes Cluster using Minikube, execute the following command:

```minikube
minikube start --driver=docker
```
### Deploying the Containerized applications to the Minikube Kubernetes Cluster
You will deploy the containerized applications to the Minikube Kubernetes Cluster using the [Kubernetes CLI](https://kubernetes.io/docs/tasks/tools/). Kubernetes CLI (`kubectl`) is a powerful command line interface tool that assists in the deployment of any containerized applications to a created Kubernetes Cluster. You can interact with the containerized applications using the `kubectl` commands and access their resources.

You need to install the Kubernetes CLI using the following command:

```choco
choco install kubernetes-cli
```
To check the installed version, use the following command:

```kubectl
choco install kubernetes-cli
```
To deploy the containerized applications, we need to create a `node-js-deployment.yaml` and `react-js-deployment.yaml` files. Kubernetes CLI will use these two files and deploy the two containerized applications.

### Creating the `node-js-deployment.yaml` file
In the project working directory, create a file named `node-js-deployment.yaml` and paste the following code:

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: node-js-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: node-js
  template:
    metadata:
      labels:
        app: node-js
    spec:
      containers:
      - name: node-js
        image: bravinwasike/node-js
        resources:
          limits:
            memory: "356Mi"
            cpu: "500m"
        ports:
        - containerPort: 4000

---

apiVersion: v1
kind: Service
metadata:
  name: node-js-service
spec:
  type: LoadBalancer
  selector:
    app: node-js
  ports:
  - port: 4000
    targetPort: 4000
    protocol: TCP
```
The file consists of two parts: Deployment and Service.

1. Deployment
This part of the file specifies the number of application pods that will run after the deployment. Pods are multiple instances or replicas of the same containerized application. It also shows the port the container will be running and resource limits for each application pod. It also shows the Docker image that will create the containers during deployment. You will use `bravinwasike/node-js` image from Docker Hub.

2. Service
It distributes the containerized application's traffic to the running pods equally. It also exposes the running application to be accessed outside the Kubernetes cluster. It assigns an External IP address to the containerized application. You can use it to access the application in a web browser.

### Creating the `react-js-deployment.yaml` file
In the project working directory, create a file named `react-js-deployment.yaml` and paste the following code:

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: react-js-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: react-js
  template:
    metadata:
      labels:
        app: react-js
    spec:
      containers:
      - name: react-js
        image: bravinwasike/react-js
        resources:
          limits:
            memory: "356Mi"
            cpu: "500m"
        ports:
        - containerPort: 3000

---

apiVersion: v1
kind: Service
metadata:
  name: react-js-service
spec:
  type: LoadBalancer
  selector:
    app: react-js
  ports:
  - protocol: TCP
    port: 3000
    targetPort: 3000
```
To deploy the two containerized applications to the Minikube Kubernetes cluster, apply the following commands:

```kubectl
kubectl apply -f node-js-deployment
kubectl apply -f react-js-deployment
```
To see the deployments, run this command:

```kubectl
kubectl get deployments
```
You can see the two deployments described in the two `.yaml` files:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ybhyyn6k4xntu51i2b9n.png)

#### Getting the containerized application pods
To get the running pods, run this command

```kubectl
kubectl get pods
```
The running pods output:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ynkz66mo96w8cz6x4uhx.png)

#### Getting the containerized applications service
To get the containerized applications service, run this command:

```kubectl
kubectl get service
```
The application services output:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pt8o5fyk582kebmidh27.png)

You have two application services described in the two `.yaml` files. The two services are running, but the `EXTERNAL-IP` is `pending`. You will expose the two services to access the applications outside the Kubernetes cluster in a web browser.

### Exposing the two services
For Minikube to assign an `EXTERNAL-IP` and expose the two services, run these commands for each of the services:

- `node-js-service`
For the `node-js-service`, run the following command:

```minikube
minikube command node-js-service
```
The code will expose the service and assign http://127.0.0.1:3215/ as  the `EXTERNAL-IP` as shown below:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/80p1ohfwg6cieuebhkx9.png)

You can access the application in the web browser using http://127.0.0.1:3215/:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/teosvrfp9fnzl2wm87xx.png)

- `react-js-service`
For the `react-js-service`, run the following command:

```minikube
minikube service react-js-service
```
The Minikube command will expose the service and assign http://127.0.0.1:2910 as the `EXTERNAL-IP` as shown below:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fcw18mum4fuy45xqxcow.png)

Before you access the `react-js-service`, ensure the exposed `node-js-service` is still running in your browser. To access the `react-js-service` in the web browser, click on this URL http://127.0.0.1:2910:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q5zxb9y6h4lavgm61a90.png)

### Conclusion
In this tutorial, you have learned how to deploy React.js and Node.js Dockerised containers to the Kubernetes Cluster. You started with an Express back-end server using Node.js. You then created a front-end web application using React.js and connected the two applications. After seting up the Node.js Express server and React.js web application, you used Docker to containerize the two applications. 

You created two stand-alone Docker containers. You created a Kubernetes Cluster that runs on our local machine using Minikube. You finally deployed the two containerized applications to the Kubernetes Cluster and accessed the application services. You can access the complete code [here](https://github.com/Bravinsimiyu/react-node-app). 

If you like this tutorial let's connect on [Twitter](https://twitter.com/wasike_bravin). Thanks for Reading and Happy Deployment!