Deploy a React application to Kubernetes in 5 easy steps

Kubernetes is currently the de-facto standard for deploying applications in the cloud. Every major cloud provider offers a dedicated Kubernetes service (eg. Google Cloud with GKE, AWS with EKS, etc.) to deploy applications in a Kubernetes cluster.

There are many reasons for choosing Kubernetes for deploying your React application:

unified and standardized deployment model across the cloud providers

robustness against downtime as several containers are deployed (horizontal scaling)

handling peak traffic with auto-scaling

zero-downtime deployments, canary deployments, etc.

simple A/B testing

With this post, I'll demonstrate how to deploy a React application to a Kubernetes cluster with five easy steps. To follow the article you just need basic Docker knowledge.

As we all want quick feedback while learning a new topic I'll use a local Kubernetes cluster for this example. You can spin up this local Kubernetes cluster in minutes if you have a Docker engine with Kubernetes support installed on your machine. This is available since version 18.06.0 for both Docker Desktop for Windows/Mac.

Let's get started...

Step 1: Create the React application

I start off with a fresh React application created with create-react-app from Facebook:

This will create all the required configuration and files to start developing a new React application.

Make sure you are able to start and access the React application on your local machine at http://localhost:3000 using npm start. For the further sections, we need the optimized production build of the React application which is created with:

If you have an existing React application you can skip this section and continue with the next one. Just make sure you have the production build of your application available at build/.

Step 2: Dockerize the React application

For deploying the React application to Kubernetes, we need to package it inside a container. Kubernetes supports several container engines, but Docker is currently the most adopted one.

To create a Docker container we need a Dockerfile at the root level of our React application folder. This file defines what OS is used, how it is configured and what other applications are running inside this container.

For this example, I'm using nginx to serve the content of the React application and the simplest Dockerfile looks like the following:

FROM nginx:1.17
COPY build/ /usr/share/nginx/html

Our Docker container inherits everything from the official nginx:1.17 Docker image and just copies the React production build to the container.

To speed up the creation of the Docker container, make sure you add a .dockerignore to your project to exclude the node_modules from being sent to the Docker context:

node_modules

Once you have your React production build in place, start your Docker engine and execute the following command to create the Docker image:

Step 4: Upload the Docker image to your container registry

To be able to pull the Docker image within the Kubernetes cluster, we need to upload the image to a Docker registry. For a cloud deployment, you usually get a dedicated registry from the cloud provider to upload your image. As we are deploying the application to a local cluster, we need a local Docker registry.

Step 5: Deploy the React application

Usually, every Kubernetes object (service, pod, deployment, etc.) is described in a .yaml file but .json is also possible.

For deploying the React application to Kubernetes we need a so-called deployment. This Kubernetes entity makes sure our application will have as many replicas (parallel pods) as we define. In addition, we can define the Docker image we want to use, what ports are used and further metadata for our application:

With just the deployment we wouldn't be able to access our application from outside. To expose applications, Kubernetes offers a so-called service. Using a service we can define which ports to expose to the cluster/outside.

There are several different types of a Kuberntes service and I'm choosing the simplest one for your example: NodePort. This type will expose a defined port on every node in our Kubernetes cluster (with the local Kubernetes cluster, we just have one node) and map it to an application's port: