Host React app on Nginx in Docker and Kubernetes
Today we’ll learn how to host your React Docker app on NGINX inside Docker and Kubernetes We’ll take a sample React app and host it on NGINX web server inside Docker. Then we’ll export the Docker image and import it into Kubernetes. Finally we’ll host this imported docker image in Kubernetes on Ubuntu using microk8s. We’ll also learn how to scale and load balance your app.
As usual, we’ll focus only on Ubuntu Server based terminal commands. No GUI commands. We’ll be using microk8s toolset of Ubuntu. Microk8s is not a subset but a full upstream version of Kubernetes. Microk8s makes it easy for a developer to install Kubernetes on Ubuntu with great default options. It also makes hosting and managing images easier.
- Create sample React app.
- Host the React app on NGINX web server inside Docker.
- Export the app image from Docker into a file.
- Import the docker image file in Kubernetes.
- Host the docker app in Kubernetes.
- Install nodejs, npm and default React app.
- Create a production build of the React app.
- Install docker.
- Create a Dockerfile file to create an image of a production build of your React app with NGINX.
- Export the docker image into a file.
- Install microk8s (Kubernetes).
- Enable required services for Kubernetes.
- Import the docker image.
- Host the app image in Kubernetes.
- Scale and load balance your app.
Here we go!
Note: To avoid typing sudo everytime, use
sudo -s, and then enter password. But for the sake of completeness, I’ll be prefixing the commands with
sudo where ever required.
1. Install nodejs, npm and default React app
sudo apt update sudo apt upgrade sudo apt-get install nodejs sudo apt-get install npm
Install the default React app
npm install -g create-react-app create-react-app --version
Create the hello world app and check if it is running fine
create-react-app first-react cd ./first-react npm start
If the output looks fine, then the first App is running. Press Ctrl-C to exit.
2. Create a production build of the React app
sudo npm run build
This will create a build folder and ill contain a production ready site.
3. Install Docker
sudo apt-get install docker.io sudo systemctl enable docker sudo systemctl start docker
4. Create a Dockerfile file to create an image of a production build of your React app with NGINX
nano Dockerfile and paste the following contents:
#Based on Node.js, to build and compile the frontend FROM node as build WORKDIR /app COPY package*.json /app/ RUN npm install COPY ./ /app/ RUN npm run build # Stage 1, based on Nginx, to have only the compiled app, ready for production with Nginx FROM nginx COPY --from=build /app/build /usr/share/nginx/html
Press Ctrl-S and Ctrl-X to exit.
Build your Docker image
docker build -t first-react-app .
You can verify the contents of the image. You can bash into the image and check the contents of the file system.
docker run -it first-react-app bash
Notes about the Dockerfile
- You have two FROM statements. The first FROM downloads a node image, builds you React application
- The second FROM statement, copies the contents from first image, discards the first image, and builds a new image with NGINX inside it.
- The line
-from=build /app/buildallows you to copy contents from your first image into the second image. The build word after
-from=comes from the first line in Dockerfile –
- You are chaining image building. This is officially called a multi-stage build.
- Important note: This new image only has the production ready build of your App that site hosted in NGINX. You don’t need nodejs or npm installed or running inside the image.
5. Export the docker image into a file
docker save first-react-app > first-react-app.tar
This creates a .tar file around 137 MB in size for this scenario.
6. Install microk8s (Kubernetes)
snap install microk8s --classic
This will install microk8s (Kubernetes) in a single command.
Important note: For Kubernetes here you have to prefix all your commands with
microk8s before typing
kubectl. This can be tedious. To enable you to skip typing
microk8s all the time, type:
snap alias microk8s.kubectl kubectl
To revert back, type:
snap unalias kubectl
Check which services are enabled/disabled
7. Enable required services for Kubernetes
microk8s enable dns dashboard
8. Import the docker image
microk8s ctr image import first-react-app.tar
Note that this imports the image docker.io namespace –
Check the images installed in current Kubetnetes
microk8s ctr images ls
To check whether our image is imported successfully
microk8s ctr images ls | grep "first-react-app"
9. Host the app image in Kubernetes
.yaml file to create a Kubernetes deployment.
Paste the following contents inside
apiVersion: apps/v1 kind: Deployment metadata: name: first-react-deployment labels: app: first-react-app spec: replicas: 5 selector: matchLabels: app: first-react-app template: metadata: labels: app: first-react-app spec: containers: - name: first-react-app image: docker.io/library/first-react-app:latest imagePullPolicy: Never ports: - containerPort: 80
Important note: If you do not specify
imagePullPolicy: Never in the
.yaml file, it will make your life miserable. Your deployment will not get created since there is a default policy getting applied while pulling the image for deployment. Since you are developing initially and to make things easier, we skipped applying pull policy rules.
10. Scale and load balance your app
As you might have observed, in the .yaml file we had mentioned
replicas: 5. This will scale your app to 5 container instances for load balancing.
Pods in Kubernetes are smallest instance which hosts your container. Technically, a pod can have multiple containers, but for simplicity, we will assume it has only one instance of our running container.
So when you run this command –
microk8s kubectl get pods, you’ll get.
NAME READY STATUS RESTARTS AGE first-react-deployment-5cb789d84f-5jf47 1/1 Running 0 9m42s first-react-deployment-5cb789d84f-kll6h 1/1 Running 0 9m42s first-react-deployment-5cb789d84f-qjlv8 1/1 Running 0 9m42s first-react-deployment-5cb789d84f-s7kgl 1/1 Running 0 9m42s first-react-deployment-5cb789d84f-sztsd 1/1 Running 0 9m42s
Since we had mentioned 5 replicas, your app is running in 5 different pods. You can also run
microk8s kubectl get all
NAME READY STATUS RESTARTS AGE pod/first-react-deployment-5cb789d84f-5jf47 1/1 Running 0 33m pod/first-react-deployment-5cb789d84f-kll6h 1/1 Running 0 33m pod/first-react-deployment-5cb789d84f-qjlv8 1/1 Running 0 33m pod/first-react-deployment-5cb789d84f-s7kgl 1/1 Running 0 33m pod/first-react-deployment-5cb789d84f-sztsd 1/1 Running 0 33m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.152.183.1 <none> 443/TCP 95m NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/first-react-deployment 5/5 5 5 33m NAME DESIRED CURRENT READY AGE replicaset.apps/first-react-deployment-5cb789d84f 5 5 5 33m
As you can see, out app is still not exposed in the
To finally expose our deployment, type:
microk8s kubectl expose deployment first-react-deployment --type LoadBalancer --name react-deployment-service --external-ip=192.168.26.133
You have now exposed the service to be usable externally. You can now type –
microk8s kubectl get all
NAME READY STATUS RESTARTS AGE pod/first-react-deployment-5cb789d84f-5jf47 1/1 Running 0 40m pod/first-react-deployment-5cb789d84f-kll6h 1/1 Running 0 40m pod/first-react-deployment-5cb789d84f-qjlv8 1/1 Running 0 40m pod/first-react-deployment-5cb789d84f-s7kgl 1/1 Running 0 40m pod/first-react-deployment-5cb789d84f-sztsd 1/1 Running 0 40m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.152.183.1 <none> 443/TCP 101m service/react-deployment-service LoadBalancer 10.152.183.230 192.168.26.133 80:32751/TCP 33s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/first-react-deployment 5/5 5 5 40m NAME DESIRED CURRENT READY AGE replicaset.apps/first-react-deployment-5cb789d84f 5 5 5 40m
Alternatively you can also type for an exhaustive output.
microk8s kubectl get all --all-namespaces
Inspect a single pod
kubectl describe pod first-react-deployment-5cb789d84f-5jf47
Replace the pod name with your own.
Hurray! You have finished deploying and exposing your first React App and scaled it to 5 instances. Kubernetes will also load balance it for you automatically.
Check your site by typing the following since this is your Load Balancer IP address and is exposed on port 80.
Check out this line from the output –
service/react-deployment-service LoadBalancer 10.152.183.230 192.168.26.133 80:32751/TCP 33s
Since you site is also exposed to external machines on port 32751 on the network, you can type this from an external machine on the network.
Yes! we learnt how to host your React Docker app on NGINX inside Docker and Kubernetes. Hope this helps you. If you have questions you can send them to email@example.com