Deploying a MERN Stack App with Kubernetes 🚀

Deploying a MERN Stack App with Kubernetes 🚀

Hello developers 👋, My name is Md taqui imam, i am a Full Stack web developer, today i will tell you "how you can deploy a MERN stack app in Kubernetes".

In today's world, most applications are built using microservices architectures and container technologies like Docker. Kubernetes has emerged as the defacto platform for orchestrating containers at scale across on-premise and cloud infrastructures.

In this detailed post, we will deploy a full-fledged MERN (MongoDB, Express, React, Node.js) stack application on Kubernetes. The MERN stack is one of the most popular techniques for building modern web apps, combining React for the frontend, Express for the API backend and MongoDB for data storage.

Kubernetes provides a powerful platform to run stateful and stateless containers, handle service discovery, load balancing, auto-scaling, upgrades and more - all with declarative configurations and minimal maintenance. Let's delve into setting up a development environment, deploying the services and exploring key Kubernetes concepts.

## Setting Up the Development Environment

The first step is to install the necessary tools on your development machine:

- Docker - Used to build container images for each component of our application. Docker simplifies packaging code and dependencies into portable images.

- Kubectl - The Kubernetes command line client that allows us to interact with the Kubernetes API server and manage the cluster. We will use it to deploy and manage application resources.

- Minikube - A tool that runs a single-node Kubernetes cluster locally for testing and development purposes. It provisions a Virtual Machine, installs Kubernetes and configures the control plane. This gives us an isolated test environment without the overhead of a full production cluster.

To install these, follow the documentation for your operating system. Once installed, we can initialize Minikube:

```

minikube start

```

This will provision a VM, download a Kubernetes version, configure RBAC and pods network etc. To verify it's running correctly:

```

kubectl cluster-info

```

The cluster API endpoint, Kubernetes master location and number of nodes should be displayed.

Now our development environment is set up to deploy containers and experiment with Kubernetes features on a local single-node cluster.

## Containerizing the Application Components

The next step is building Docker images for each component of our MERN application - MongoDB, Express and React. We'll store these images in a Docker registry like Docker Hub for later deployment.

For MongoDB, create a Dockerfile that clones the latest code, sets up configuration and exposes the default port:

```dockerfile

FROM mongo:latest

COPY mongod.conf /etc/mongod.conf

EXPOSE 27017

```

Build and tag the image:

```

docker build -t myuser/mongodb .

docker push myuser/mongodb

```

Similarly, create Dockerfiles and images for the Express API and React front-end services. The API Dockerfile would COPY the code and install dependencies before exposing the app port.

Now we have containerized the application components independently, along with any dependencies or configuration baked in. These images form the base units that Kubernetes will schedule and run as "pods".

## Configuring Secrets and ConfigMaps

When deploying to Kubernetes, we need a secure and flexible way to inject configuration and credentials into containers at runtime. For this, Kubernetes supports Secrets and ConfigMaps.

Secrets hold sensitive data like passwords, keys or tokens in a base64 encoded format. ConfigMaps store non-sensitive configuration data like environment variables or properties files.

For our app, we will define:

- A Secret for the MongoDB username and password

- A ConfigMap for database URL, Node environment variables

The secret.yaml:

```yaml

apiVersion: v1

kind: Secret

metadata:

name: mongo-secret

stringData:

password: supersecurepass

```

The configmap.yaml:

```yaml

apiVersion: v1

kind: ConfigMap

metadata:

name: app-config

data:

MONGO_URI: mongodb://usr:pass@mongodb:27017/app

NODE_ENV: production

```

We can now apply these resources to Kubernetes:

```

kubectl apply -f secret.yaml

kubectl apply -f configmap.yaml

```

This securely stores sensitive values in etcd while exposing non-sensitive data to containers.

## Deploying MongoDB

With container images and configurations ready, it's time to deploy MongoDB as a Kubernetes resource. We'll create a Deployment to launch replicated pods behind a Service for discovery.

The mongodb-deployment.yaml defines:

- mongodb image from prepared Dockerfile

- Pod spec with resources, ports and volumes

- Pulls password from mongo-secret

```yaml

apiVersion: apps/v1

kind: Deployment

metadata:

name: mongodb

spec:

replicas: 1

selector:

matchLabels:

app: mongodb

template:

metadata:

labels:

app: mongodb

spec:

containers:

- name: mongodb

image: myuser/mongodb

envFrom:

- secretRef:

name: mongo-secret

ports:

- containerPort: 27017

```

Next, a mongodb-service.yaml exposes port 27017 within the cluster:

```yaml

apiVersion: v1

kind: Service

metadata:

name: mongodb

spec:

type: ClusterIP

ports:

- port: 27017

selector:

app: mongodb

```

Now apply both configs:

```

kubectl apply -f mongodb-deployment.yaml

kubectl apply -f mongodb-service.yaml

```

Kubernetes will create MongoDB pods and make them discoverable via DNS.

## Deploying the Express API

Now for the Express backend API. Create an express-deployment.yaml:

- Node.js image from prepared Dockerfile

- Environment from app-config ConfigMap

- Port 8080 exposed

```yaml

apiVersion: apps/v1

kind: Deployment

metadata:

name: express

spec:

replicas: 1

selector:

matchLabels:

app: express

template:

metadata:

labels:

app: express

spec:

containers:

- name: express

image: myuser/express

envFrom:

- configMapRef:

name: app-config

ports:

- containerPort: 8080

```

An express-service.yaml exposes port 8080 externally:

```yaml

apiVersion: v1

kind: Service

metadata:

name: express

spec:

type: NodePort

ports:

- port: 8080

nodePort: 30001

selector:

app: express

```

Deploy both and the Express API is now available on port 30001!

## Deploying the React Frontend

For the frontend, create a react-deployment.yaml:

- React image from Dockerfile

- Mount volumes for building

- Port 80 exposed

```yaml

apiVersion: apps/v1

kind: Deployment

metadata:

name: react

spec:

selector:

matchLabels:

app: react

template:

metadata:

labels:

app: react

spec:

containers:

- name: react

image: myuser/react

ports:

- containerPort: 80

```

A react-service.yaml exposes port 80 internally:

```yaml

apiVersion: v1

kind: Service

metadata:

name: react

spec:

type: ClusterIP

ports:

- port: 80

selector:

app: react

```

Deploy and the React SPA is now being served from Kubernetes!

## Accessing the Application

Now that all services are deployed, we can test the full MERN stack running on Kubernetes.

By default, the React service is only reachable within the cluster. We can port-forward it locally:

```

kubectl port-forward svc/react 8080:80

```

Now visit http://localhost:8080 to view the app.

The frontend makes API calls to the Express service endpoint, which connects to MongoDB. Even though components are split, Kubernetes handles discovery and routing requests between services.

This is just the beginning - Kubernetes unlocks many more advanced capabilities around auto-scaling, easy updates, reliability guarantees and more. We've learned the basics of deploying modern applications on Kubernetes using declarative configs.

In the future, areas to explore include service meshes, Helm charts for packaging configurations, ingress controllers, monitoring solutions and more to improve the experience of running containers at scale. Kubernetes is a powerful platform for developing and deploying distributed software.

To view or add a comment, sign in

More articles by Md Taqui Imam

Explore content categories