Docker : Run a React app in a minikube
Continued from Run a React app in a docker, in this post, we'll deploy the React app to Kubenetes cluster, actually, to minikube.
First, we'll deploy a react default app and then our hello-world app.
npm (Node Package Manager) is a package manager for the JavaScript programming language. It has become the de facto package manager for the web. It is installed with Node.js
$ npm -v 6.14.5 $ node -v v11.9.0
We will use npm to install Create React App CLI globally:
$ npm install -g create-react-app /usr/local/bin/create-react-app -> /usr/local/lib/node_modules/create-react-app/index.js + create-react-app@3.4.1 added 98 packages from 46 contributors in 8.297s
Let's start off with a fresh React application created with create-react-app. So, react App the works by running the following command:
$ npx create-react-app react-minikube ... Installing packages. This might take a couple of minutes. Installing react, react-dom, and react-scripts with cra-template... ...
This generates all the required configuration and files, folders, and libraries to start developing a new React application.
We can see three top level sub-folders:
- /node_modules: Where all of the external libraries used to piece together the React app are located. We shouldn't modify any of the code inside this folder as that would be modifying a third party library, and our changes would be overwritten the next time we run the npm install command.
- /public: Assets that aren't compiled or dynamically generated are stored here. These can be static assets like logos or the robots.txt file.
- /src: Where we'll be spending most of our time. This folder contains all of our React components, external CSS files, and dynamic assets that we'll bring into our component files.
The package.json file outlines all the settings for the React app:
- name is the name of our app
- version is the current version
- "private": true is a failsafe setting to avoid accidentally publishing our app as a public package within the npm ecosystem.
- dependencies contains all the required node modules and versions required for the application. Here, it contains htree dependencies, which allow us to use react, react-dom, and react-scripts in our JavaScript. In the screenshot above, the react version specified is ^16.13.1. This means that npm will install the most recent major version matching 16.x.x. We may also see something like ~1.2.3 in package.json, which will only install the most recent minor version matching 1.2.x.
- scripts specifies aliases that we can use to access some of the react-scripts commands in a more efficient manner.
For example running
npm test
in our command line will runreact-scripts test --env=jsdom
behind the scenes.
We must be in the folder where package.json is:
$ cd react-minikube
Start the React app by typing npm start
into the terminal.
$ npm start ... Compiled successfully! You can now view hello-world in the browser. Local: http://localhost:3000 On Your Network: http://10.0.0.161:3000 Note that the development build is not optimized. To create a production build, use npm run build.
Changes made to the React app code are automatically shown in the browser thanks to hot reloading (any changes we make to the running app's code will automatically refresh the app in the browser to reflect those changes).
If everything goes well, a new browser tab should open showing the placeholder React component:
Edit the "App.js" and save it. Then, we'll immediately see the changes on the browser.
We may want to have an optimized production build of the React application which can be created with:
$ npm run-script build > react-minikube@0.1.0 build /Users/kihyuckhong/React-Minikube/react-minikube > react-scripts build Creating an optimized production build... Compiled successfully. File sizes after gzip: 39.39 KB build/static/js/2.91e125fa.chunk.js 776 B build/static/js/runtime-main.5edc06ea.js 650 B build/static/js/main.54f008fc.chunk.js 547 B build/static/css/main.5f361e03.chunk.css ...
We can see we have the production build of our application available at build/.
To create a Docker container we need a Dockerfile at the root level of our React application folder.
$ docker --version Docker version 19.03.8, build afacb8b
We'll be using nginx to serve the content of the React application. So, add the following Dockerfile to the root of the project:
FROM nginx:stable-alpine COPY build/ /usr/share/nginx/html
As we can see our Docker container will have the official nginx Docker image and copies the React production build/ to the container.
Note that we could have used a Dockerfile using multistage build pattern as in Docker : Run a React app in a docker.
To speed up the creation of the Docker container, make sure to add a .dockerignore to our project to exclude such as node_modules from being sent to the Docker context. Here is the .dockerignore file:
node_modules npm-debug.log build .dockerignore **/.git **/.DS_Store **/node_modules
Now that have our React production build in place, we can start our Docker engine.
Let's create our Docker image:
$ docker build -t minikube-react-app . Sending build context to Docker daemon 1.138MB Step 1/2 : FROM nginx:stable-alpine ---> ab94f84cc474 Step 2/2 : COPY build/ /usr/share/nginx/html ---> 7aa20584ef36 Successfully built 7aa20584ef36 Successfully tagged minikube-react-app:latest $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE minikube-react-app latest 7aa20584ef36 28 seconds ago 21.8MB
Before we run our app on a kubernetes cluster, we need to put our docker image to DockerHub:
$ docker build -t dockerbogo/minikube-react-app:v1 . Sending build context to Docker daemon 1.136MB Step 1/2 : FROM nginx:stable-alpine ---> ab94f84cc474 Step 2/2 : COPY build/ /usr/share/nginx/html ---> Using cache ---> dc86e2209cf1 Successfully built dc86e2209cf1 Successfully tagged dockerbogo/minikube-react-app:v1 $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE dockerbogo/minikube-react-app v1 dc86e2209cf1 28 seconds ag 21.8MB $ docker login $ docker push dockerbogo/minikube-react-app:v1
Let's start our minikube:
$ minikube start
Before we run our app on a kubernetes cluster, we need to put our docker image to DockerHub:
$ docker build -t dockerbogo/minikube-react-app:v1 . Sending build context to Docker daemon 1.136MB Step 1/2 : FROM nginx:stable-alpine ---> ab94f84cc474 Step 2/2 : COPY build/ /usr/share/nginx/html ---> Using cache ---> dc86e2209cf1 Successfully built dc86e2209cf1 Successfully tagged dockerbogo/minikube-react-app:v1 $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE dockerbogo/minikube-react-app v1 dc86e2209cf1 28 seconds ag 21.8MB $ docker login $ docker push dockerbogo/minikube-react-app:v1
Now, we are ready to deploy our app to minikube with the following deployment.yaml:
kind: Deployment apiVersion: apps/v1 metadata: name: minikube-react-app spec: replicas: 2 selector: matchLabels: app: minikube-react-app template: metadata: labels: app: minikube-react-app spec: containers: - name: minikube-react-app image: dockerbogo/minikube-react-app:v1 imagePullPolicy: Always ports: - containerPort: 80 resources: requests: memory: "100Mi" cpu: "300m" limits: memory: "200Mi" cpu: "600m" restartPolicy: Always --- kind: Service apiVersion: v1 metadata: name: minikube-react-app spec: type: NodePort ports: - port: 80 targetPort: 80 protocol: TCP nodePort: 31000 selector: app: minikube-react-app
$ kubectl apply -f deployment.yaml deployment.apps/minikube-react-app created service/minikube-react-app created $ kubectl get pods NAME READY STATUS RESTARTS AGE minikube-react-app-68b4d9857f-ffpmd 1/1 Running 0 68s minikube-react-app-68b4d9857f-srt9m 1/1 Running 0 68s $ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE minikube-react-app NodePort 10.100.103.80 <none> 80:31000/TCP 74s $ kubectl get deployment NAME READY UP-TO-DATE AVAILABLE AGE minikube-react-app 2/2 2 2 83s
We can access the app via
$(minikube ip):NodePort
as shown below:
We can update our app image and deploy with a new deployment.yaml:
kind: Deployment apiVersion: apps/v1 metadata: name: minikube-react-app spec: replicas: 2 selector: matchLabels: app: minikube-react-app template: metadata: labels: app: minikube-react-app spec: containers: - name: minikube-react-app image: dockerbogo/minikube-react-app:v2 imagePullPolicy: Always ports: - containerPort: 80 resources: requests: memory: "100Mi" cpu: "300m" limits: memory: "200Mi" cpu: "600m" restartPolicy: Always --- kind: Service apiVersion: v1 metadata: name: minikube-react-app spec: type: NodePort ports: - port: 80 targetPort: 80 protocol: TCP nodePort: 31000 selector: app: minikube-react-app
Before we update our app, we need to put our docker image to DockerHub:
$ docker build -t dockerbogo/minikube-react-app:v2 . Sending build context to Docker daemon 1.136MB Step 1/2 : FROM nginx:stable-alpine ---> ab94f84cc474 Step 2/2 : COPY build/ /usr/share/nginx/html ---> Using cache ---> dc86e2209cf1 Successfully built dc86e2209cf1 Successfully tagged dockerbogo/minikube-react-app:v2 $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE dockerbogo/minikube-react-app v1 dc86e2209cf1 28 seconds ago 21.8MB $ docker login $ docker push dockerbogo/minikube-react-app:v2
$ kubectl apply -f deployment.yaml $ kubectl get pods NAME READY STATUS RESTARTS AGE minikube-react-app-68b4d9857f-6kt2v 1/1 Running 0 17s minikube-react-app-68b4d9857f-q4h87 1/1 Running 0 17s $ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE minikube-react-app NodePort 10.100.15.100 <none> 80:31000/TCP 48s $ kubectl get deployment NAME READY UP-TO-DATE AVAILABLE AGE minikube-react-app 2/2 2 2 83s
We can access the updated app via
$(minikube ip):NodePort
as before.
Docker & K8s
- Docker install on Amazon Linux AMI
- Docker install on EC2 Ubuntu 14.04
- Docker container vs Virtual Machine
- Docker install on Ubuntu 14.04
- Docker Hello World Application
- Nginx image - share/copy files, Dockerfile
- Working with Docker images : brief introduction
- Docker image and container via docker commands (search, pull, run, ps, restart, attach, and rm)
- More on docker run command (docker run -it, docker run --rm, etc.)
- Docker Networks - Bridge Driver Network
- Docker Persistent Storage
- File sharing between host and container (docker run -d -p -v)
- Linking containers and volume for datastore
- Dockerfile - Build Docker images automatically I - FROM, MAINTAINER, and build context
- Dockerfile - Build Docker images automatically II - revisiting FROM, MAINTAINER, build context, and caching
- Dockerfile - Build Docker images automatically III - RUN
- Dockerfile - Build Docker images automatically IV - CMD
- Dockerfile - Build Docker images automatically V - WORKDIR, ENV, ADD, and ENTRYPOINT
- Docker - Apache Tomcat
- Docker - NodeJS
- Docker - NodeJS with hostname
- Docker Compose - NodeJS with MongoDB
- Docker - Prometheus and Grafana with Docker-compose
- Docker - StatsD/Graphite/Grafana
- Docker - Deploying a Java EE JBoss/WildFly Application on AWS Elastic Beanstalk Using Docker Containers
- Docker : NodeJS with GCP Kubernetes Engine
- Docker : Jenkins Multibranch Pipeline with Jenkinsfile and Github
- Docker : Jenkins Master and Slave
- Docker - ELK : ElasticSearch, Logstash, and Kibana
- Docker - ELK 7.6 : Elasticsearch on Centos 7
- Docker - ELK 7.6 : Filebeat on Centos 7
- Docker - ELK 7.6 : Logstash on Centos 7
- Docker - ELK 7.6 : Kibana on Centos 7
- Docker - ELK 7.6 : Elastic Stack with Docker Compose
- Docker - Deploy Elastic Cloud on Kubernetes (ECK) via Elasticsearch operator on minikube
- Docker - Deploy Elastic Stack via Helm on minikube
- Docker Compose - A gentle introduction with WordPress
- Docker Compose - MySQL
- MEAN Stack app on Docker containers : micro services
- MEAN Stack app on Docker containers : micro services via docker-compose
- Docker Compose - Hashicorp's Vault and Consul Part A (install vault, unsealing, static secrets, and policies)
- Docker Compose - Hashicorp's Vault and Consul Part B (EaaS, dynamic secrets, leases, and revocation)
- Docker Compose - Hashicorp's Vault and Consul Part C (Consul)
- Docker Compose with two containers - Flask REST API service container and an Apache server container
- Docker compose : Nginx reverse proxy with multiple containers
- Docker & Kubernetes : Envoy - Getting started
- Docker & Kubernetes : Envoy - Front Proxy
- Docker & Kubernetes : Ambassador - Envoy API Gateway on Kubernetes
- Docker Packer
- Docker Cheat Sheet
- Docker Q & A #1
- Kubernetes Q & A - Part I
- Kubernetes Q & A - Part II
- Docker - Run a React app in a docker
- Docker - Run a React app in a docker II (snapshot app with nginx)
- Docker - NodeJS and MySQL app with React in a docker
- Docker - Step by Step NodeJS and MySQL app with React - I
- Installing LAMP via puppet on Docker
- Docker install via Puppet
- Nginx Docker install via Ansible
- Apache Hadoop CDH 5.8 Install with QuickStarts Docker
- Docker - Deploying Flask app to ECS
- Docker Compose - Deploying WordPress to AWS
- Docker - WordPress Deploy to ECS with Docker-Compose (ECS-CLI EC2 type)
- Docker - WordPress Deploy to ECS with Docker-Compose (ECS-CLI Fargate type)
- Docker - ECS Fargate
- Docker - AWS ECS service discovery with Flask and Redis
- Docker & Kubernetes : minikube
- Docker & Kubernetes 2 : minikube Django with Postgres - persistent volume
- Docker & Kubernetes 3 : minikube Django with Redis and Celery
- Docker & Kubernetes 4 : Django with RDS via AWS Kops
- Docker & Kubernetes : Kops on AWS
- Docker & Kubernetes : Ingress controller on AWS with Kops
- Docker & Kubernetes : HashiCorp's Vault and Consul on minikube
- Docker & Kubernetes : HashiCorp's Vault and Consul - Auto-unseal using Transit Secrets Engine
- Docker & Kubernetes : Persistent Volumes & Persistent Volumes Claims - hostPath and annotations
- Docker & Kubernetes : Persistent Volumes - Dynamic volume provisioning
- Docker & Kubernetes : DaemonSet
- Docker & Kubernetes : Secrets
- Docker & Kubernetes : kubectl command
- Docker & Kubernetes : Assign a Kubernetes Pod to a particular node in a Kubernetes cluster
- Docker & Kubernetes : Configure a Pod to Use a ConfigMap
- AWS : EKS (Elastic Container Service for Kubernetes)
- Docker & Kubernetes : Run a React app in a minikube
- Docker & Kubernetes : Minikube install on AWS EC2
- Docker & Kubernetes : Cassandra with a StatefulSet
- Docker & Kubernetes : Terraform and AWS EKS
- Docker & Kubernetes : Pods and Service definitions
- Docker & Kubernetes : Service IP and the Service Type
- Docker & Kubernetes : Kubernetes DNS with Pods and Services
- Docker & Kubernetes : Headless service and discovering pods
- Docker & Kubernetes : Scaling and Updating application
- Docker & Kubernetes : Horizontal pod autoscaler on minikubes
- Docker & Kubernetes : From a monolithic app to micro services on GCP Kubernetes
- Docker & Kubernetes : Rolling updates
- Docker & Kubernetes : Deployments to GKE (Rolling update, Canary and Blue-green deployments)
- Docker & Kubernetes : Slack Chat Bot with NodeJS on GCP Kubernetes
- Docker & Kubernetes : Continuous Delivery with Jenkins Multibranch Pipeline for Dev, Canary, and Production Environments on GCP Kubernetes
- Docker & Kubernetes : NodePort vs LoadBalancer vs Ingress
- Docker & Kubernetes : MongoDB / MongoExpress on Minikube
- Docker & Kubernetes : Load Testing with Locust on GCP Kubernetes
- Docker & Kubernetes : MongoDB with StatefulSets on GCP Kubernetes Engine
- Docker & Kubernetes : Nginx Ingress Controller on Minikube
- Docker & Kubernetes : Setting up Ingress with NGINX Controller on Minikube (Mac)
- Docker & Kubernetes : Nginx Ingress Controller for Dashboard service on Minikube
- Docker & Kubernetes : Nginx Ingress Controller on GCP Kubernetes
- Docker & Kubernetes : Kubernetes Ingress with AWS ALB Ingress Controller in EKS
- Docker & Kubernetes : Setting up a private cluster on GCP Kubernetes
- Docker & Kubernetes : Kubernetes Namespaces (default, kube-public, kube-system) and switching namespaces (kubens)
- Docker & Kubernetes : StatefulSets on minikube
- Docker & Kubernetes : RBAC
- Docker & Kubernetes Service Account, RBAC, and IAM
- Docker & Kubernetes - Kubernetes Service Account, RBAC, IAM with EKS ALB, Part 1
- Docker & Kubernetes : Helm Chart
- Docker & Kubernetes : My first Helm deploy
- Docker & Kubernetes : Readiness and Liveness Probes
- Docker & Kubernetes : Helm chart repository with Github pages
- Docker & Kubernetes : Deploying WordPress and MariaDB with Ingress to Minikube using Helm Chart
- Docker & Kubernetes : Deploying WordPress and MariaDB to AWS using Helm 2 Chart
- Docker & Kubernetes : Deploying WordPress and MariaDB to AWS using Helm 3 Chart
- Docker & Kubernetes : Helm Chart for Node/Express and MySQL with Ingress
- Docker & Kubernetes : Deploy Prometheus and Grafana using Helm and Prometheus Operator - Monitoring Kubernetes node resources out of the box
- Docker & Kubernetes : Deploy Prometheus and Grafana using kube-prometheus-stack Helm Chart
- Docker & Kubernetes : Istio (service mesh) sidecar proxy on GCP Kubernetes
- Docker & Kubernetes : Istio on EKS
- Docker & Kubernetes : Istio on Minikube with AWS EC2 for Bookinfo Application
- Docker & Kubernetes : Deploying .NET Core app to Kubernetes Engine and configuring its traffic managed by Istio (Part I)
- Docker & Kubernetes : Deploying .NET Core app to Kubernetes Engine and configuring its traffic managed by Istio (Part II - Prometheus, Grafana, pin a service, split traffic, and inject faults)
- Docker & Kubernetes : Helm Package Manager with MySQL on GCP Kubernetes Engine
- Docker & Kubernetes : Deploying Memcached on Kubernetes Engine
- Docker & Kubernetes : EKS Control Plane (API server) Metrics with Prometheus
- Docker & Kubernetes : Spinnaker on EKS with Halyard
- Docker & Kubernetes : Continuous Delivery Pipelines with Spinnaker and Kubernetes Engine
- Docker & Kubernetes : Multi-node Local Kubernetes cluster : Kubeadm-dind (docker-in-docker)
- Docker & Kubernetes : Multi-node Local Kubernetes cluster : Kubeadm-kind (k8s-in-docker)
- Docker & Kubernetes : nodeSelector, nodeAffinity, taints/tolerations, pod affinity and anti-affinity - Assigning Pods to Nodes
- Docker & Kubernetes : Jenkins-X on EKS
- Docker & Kubernetes : ArgoCD App of Apps with Heml on Kubernetes
- Docker & Kubernetes : ArgoCD on Kubernetes cluster
- Docker & Kubernetes : GitOps with ArgoCD for Continuous Delivery to Kubernetes clusters (minikube) - guestbook
Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization