This guide will walk you through creating a simple MERN stack application using Kubernetes, with local JSON data instead of MongoDB.
- Docker installed and configured
- Kubernetes cluster (you can use Minikube/Port Forwarding for local development)
- kubectl command-line tool installed and configured
mern-k8s-app/
├── backend/
│ ├── data/
│ │ └── items.json
│ ├── Dockerfile
│ ├── package.json
│ └── server.js
├── frontend/
│ ├── public/
│ ├── src/
│ │ ├── App.js
│ │ └── index.js
│ ├── Dockerfile
│ └── package.json
├── k8s/
│ ├── backend-deployment.yaml
│ ├── backend-service.yaml
│ ├── frontend-deployment.yaml
│ └── frontend-service.yaml
└── .dockerignore
-
Create the backend directory and navigate into it:
mkdir -p mern-k8s-app/backend cd mern-k8s-app/backend -
Initialize a new Node.js project and install dependencies:
npm init -y npm install express cors
-
Create a
datadirectory and anitems.jsonfile inside it:mkdir data echo '[ {"id": 1, "name": "Item 1"}, {"id": 2, "name": "Item 2"}, {"id": 3, "name": "Item 3"} ]' > data/items.json
-
Create
server.js:const express = require("express"); const cors = require("cors"); const fs = require("fs"); const path = require("path"); const app = express(); const PORT = process.env.PORT || 5000; // Allow requests from any origin app.use(cors({ origin: "*" })); app.use(express.json()); app.get("/api/items", (req, res) => { const items = JSON.parse( fs.readFileSync(path.join(__dirname, "data", "items.json"), "utf8") ); res.json(items); }); app.listen(PORT, () => { console.log(`Server running on port ${PORT}`); });
-
Create a
Dockerfilefor the backend:FROM node:14 WORKDIR /usr/src/app COPY package*.json ./ RUN npm install COPY . . EXPOSE 5000 CMD ["node", "server.js"]
-
Create the frontend directory and navigate into it:
cd .. npx create-react-app frontend cd frontend
-
Replace the content of
src/App.js:import React, { useState, useEffect } from "react"; function App() { const [items, setItems] = useState([]); useEffect(() => { // Use environment variable or fallback to localhost for local development const backendUrl = process.env.REACT_APP_BACKEND_URL || "http://localhost:5000"; fetch(`${backendUrl}/api/items`) .then((response) => response.json()) .then((data) => setItems(data)) .catch((error) => console.error("Error fetching items:", error)); }, []); return ( <div> <h1>Items</h1> <ul> {items.map((item) => ( <li key={item.id}>{item.name}</li> ))} </ul> </div> ); } export default App;
-
Create a
Dockerfilefor the frontend:FROM node:14 WORKDIR /usr/src/app COPY package*.json ./ RUN npm install COPY . . RUN npm run build EXPOSE 3000 CMD ["npx", "serve", "-s", "build"]
-
Build and push the backend image:
cd ../backend docker build -t your-docker-username/mern-backend:v1 . docker push your-docker-username/mern-backend:v1
-
Build and push the frontend image:
cd ../frontend docker build -t your-docker-username/mern-frontend:v1 . docker push your-docker-username/mern-frontend:v1
-
Create a
k8sdirectory in the root of your project:cd .. mkdir k8s cd k8s
-
Create
backend-deployment.yaml:apiVersion: apps/v1 kind: Deployment metadata: name: backend-deployment spec: replicas: 1 selector: matchLabels: app: backend template: metadata: labels: app: backend spec: containers: - name: backend image: your-docker-username/mern-backend:v1 ports: - containerPort: 5000
Note: Change the image to a new version if you update the backend image. Eg:
your-docker-username/mern-backend:v2 -
Create
backend-service.yaml:apiVersion: v1 kind: Service metadata: name: backend-service spec: selector: app: backend ports: - protocol: TCP port: 80 targetPort: 5000
-
Create
frontend-deployment.yaml:apiVersion: apps/v1 kind: Deployment metadata: name: frontend-deployment spec: replicas: 1 selector: matchLabels: app: frontend template: metadata: labels: app: frontend spec: containers: - name: frontend image: your-docker-username/mern-frontend:v1 ports: - containerPort: 3000
Note: Change the image to a new version if you update the frontend image. Eg:
your-docker-username/mern-frontend:v3 -
Create
frontend-service.yaml:apiVersion: v1 kind: Service metadata: name: frontend-service spec: type: LoadBalancer selector: app: frontend ports: - protocol: TCP port: 80 targetPort: 3000
-
Apply the Kubernetes configurations:
kubectl apply -f k8s/
-
Check the status of your deployments and services:
kubectl get deployments kubectl get services kubectl get pods
Use Port Forwarding to access the frontend & backend services:
-
For the frontend service:
In your first terminal:
kubectl port-forward service/frontend-service 8080:80
This forwards your local port 8080 to port 80 of the frontend service.
-
For the backend service:
Open a new terminal window and run:
kubectl port-forward service/backend-service 5000:80
This forwards your local port 5000 to port 80 of the backend service.
Now, you should have both services running and accessible:
- Frontend: http://localhost:8080
- Backend: http://localhost:5000
To remove the deployments and services:
kubectl delete -f .This setup provides a simple MERN stack application using Kubernetes, with local JSON data instead of MongoDB. The backend serves the JSON data, and the frontend displays it.