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...
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 > email@example.com 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
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:
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.
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:
- Google Kubernetes Engine (GKE) quickstart
- Azure Kubernetes Engine (AKS) quickstart
- AWS Kubernetes Engine (EKS) quickstart
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.
Usually, every Kubernetes object (
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
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:
- #HOWTO: Preview PDF files with React
- #HOWTO: MicroProfile JWT Authentication with Keycloak and React
- #HOWTO: Up- and download files with React and Spring Boot
Have fun deploying your React applications to Kubernetes,