loading...
Cover image for Deploy a React application to Kubernetes in 5 easy steps

Deploy a React application to Kubernetes in 5 easy steps

rieckpil profile image Philip Riecks Updated on ・7 min read

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:

➜ node -v
v10.16.0
➜ npm -v
6.9.0
➜ npx create-react-app react-app-kubernetes
npx: installed 91 in 5.787s

Creating a new React app in /Users/rieckpil/Desktop/react-app-kubernetes.

Installing packages. This might take a couple of minutes.
Installing react, react-dom, and react-scripts...

...

Happy hacking!

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:

➜ npm run-script build
> react-app-kubernetes@0.1.0 build /Users/rieckpil/Desktop/junk/react-app-kubernetes
> react-scripts build

Creating an optimized production build...
Compiled successfully.

File sizes after gzip:

  36.44 KB  build/static/js/2.b41502e9.chunk.js
  762 B     build/static/js/runtime~main.a8a9905a.js
  602 B     build/static/js/main.28647029.chunk.js
  517 B     build/static/css/main.2cce8147.chunk.css

...

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:

➜ docker build -t my-react-app .
Step 1/2 : FROM nginx:1.17
1.17: Pulling from library/nginx
fc7181108d40: Pull complete
d2e987ca2267: Pull complete
0b760b431b11: Pull complete
Digest: sha256:96fb261b66270b900ea5a2c17a26abbfabe95506e73c3a3c65869a6dbe83223a
Status: Downloaded newer image for nginx:1.17
 ---> f68d6e55e065
Step 2/2 : COPY build/ /usr/share/nginx/html
 ---> 35d48f28a918
Successfully built 35d48f28a918
Successfully tagged my-react-app:latest

For a more production-ready Docker container, make sure you customize the nginx configuration for your needs.

Step 3: Connect to your Kubernetes cluster

To start your local Kubernetes cluster, open the Docker Desktop preferences and switch to the Kubernetes tab:

Here you can enable the Kubernetes support. If you enable it for the first time, the cluster creation may take some time, as several Docker images are downloaded in the background.

Once your local Kubernetes cluster is running, connect to it via kubectl (if missing, download here):

➜ kubectl config use-context docker-for-desktop
Switched to context "docker-for-desktop".
➜ kubectl get nodes
NAME                 STATUS    ROLES     AGE       VERSION
docker-for-desktop   Ready     master    3d        v1.10.11
➜ kubectl cluster-info
Kubernetes master is running at https://localhost:6443
KubeDNS is running at https://localhost:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

With this Kubernetes support of Docker Desktop you'll get a local single node cluster which is nice for evaluation and learning purposes.

If you want to deploy your React application to a Kubernetes cluster in the cloud, start here:

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.

You can create a local Docker registry with the following statement:

➜ docker run -d -p 5000:5000 --restart=always --name registry registry:2

For uploading our previously created React Docker image, we have to tag the image with the hostname and port of the registry:

➜ docker tag my-react-app localhost:5000/my-react-app

And can now finally push the image to our Docker registry:

➜ docker push localhost:5000/my-react-app
The push refers to repository [localhost:5000/my-react-app]
9d9745936581: Pushed
d2f0b6dea592: Pushed
197c666de9dd: Pushed
cf5b3c6798f7: Pushed
latest: digest: sha256:66c94bdba6b06d1964a764cd14dc97d8adf202b02ab6e6fbd10b23ad4a8554a1 size: 1158

Now we are ready to deploy the application to the Kubernetes cluster.

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:

kind: Deployment
apiVersion: apps/v1
metadata:
  name: my-react-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: my-react-app
  template:
    metadata:
      labels:
        app: my-react-app
    spec:
      containers:
        - name: my-react-app
          image: localhost:5000/my-react-app
          imagePullPolicy: Always
          ports:
            - containerPort: 80
      restartPolicy: Always

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:

kind: Service
apiVersion: v1
metadata:
  name: my-react-app
spec:
  type: NodePort
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
      nodePort: 31000
  selector:
    app: my-react-app

Both the service and deployment can be added to a single .yaml file with a --- for separation. In our example, I've created one deployment.yaml file to store both:

kind: Deployment
apiVersion: apps/v1
# more ...
---
kind: Service
apiVersion: v1
# more ...

You can now use this file to deploy your application to Kubernetes with:

➜ kubectl apply -f deployment.yaml
deployment.apps "my-react-app" created
service "my-react-app" created

And can check that everything is running using:

➜ kubectl get pods
NAME                            READY     STATUS    RESTARTS   AGE
my-react-app-6c8b5c4759-fgb2q   1/1       Running   0          7m
my-react-app-6c8b5c4759-jrzzj   1/1       Running   0          7m
➜ kubectl get deployment
NAME           DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
my-react-app   2         2         2            2           7m
➜ kubectl get service
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kubernetes     ClusterIP   10.96.0.1       <none>        443/TCP        3d
my-react-app   NodePort    10.99.224.141   <none>        80:31000/TCP   7m

Once everything is up and running, visit http://localhost:31000 on your machine and you should see your React application, now served from a Kubernetes cluster:

To remove the React application from your Kubernetes cluster, just run

➜ kubectl delete service,deployment my-react-app
service "my-react-app" deleted
deployment.extensions "my-react-app" deleted

You can find the whole codebase for this example on GitHub.

For further React related posts, visit my blog:

Have fun deploying your React applications to Kubernetes,
Phil

Posted on by:

rieckpil profile

Philip Riecks

@rieckpil

I’m Philip and working with Java since university. I’m curious about the latest trends within the Java ecosystem but also highly focused on productivity & simplicity with proven Java technologies.

Discussion

pic
Editor guide
 

Hey great tutorial. In step 3, I believe an update is necessary to change the command from
$ kubectl config use-context docker-for-desktop
to
$kubectl config use-context docker-desktop

Also in the deploying to the cloud step, including deploying on OCI via: docs.cloud.oracle.com/en-us/iaas/C...

would make this tutorial even more overarching.

 

thanks for your comment. Which Docker for Desktop version are you using? For me both docker-for-desktop and docker-desktop work in step 3.

Regarding OCI: I wanted this post to focus on deploying it to a local cluster. Including now one cloud provider would require including all common providers (to be balanced). I guess each cloud provider has great documentation about how to deploy applications to their Kubernetes solution.

But indeed Oracle was missing in the quickstart links and I added it, thanks for the catch!