Todo: MERN in k8s

Alvin Lucillo
Nullify
Published in
4 min readJul 19, 2022

This article aims to explain this small, containerized Todo project written in ReactJS and NestJS and how they work together in a Kubernetes cluster. A basic understanding of the said technologies is recommended but is not required. Note that the app only provides basic features since its purpose is for demonstration only.

These are the repo and Docker image links if you’re only interested in the project. For the explanation, see other sections below.

Article Contents

1. Setting up the environment and the app
2. Project structure
3. Infrastructure

1. Setting up the environment and the app

NAME                                 READY   STATUS    RESTARTS   AGE
pod/backend-depl-6dd885554c-g696m 1/1 Running 0 8m46s
pod/frontend-depl-69dbc48fcc-qqgwc 1/1 Running 0 8m46s
pod/mongo-depl-765bbddfc5-wkhbz 1/1 Running 0 8m46s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/backend-srv ClusterIP 10.98.185.46 <none> 3001/TCP 8m46s
service/frontend-srv ClusterIP 10.97.44.16 <none> 3000/TCP 8m46s
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 10h
service/mongo-srv ClusterIP 10.99.217.211 <none> 27017/TCP 8m46s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/backend-depl 1/1 1 1 8m46s
deployment.apps/frontend-depl 1/1 1 1 8m46s
deployment.apps/mongo-depl 1/1 1 1 8m46s
NAME DESIRED CURRENT READY AGE
replicaset.apps/backend-depl-6dd885554c 1 1 1 8m46s
replicaset.apps/frontend-depl-69dbc48fcc 1 1 1 8m46s
replicaset.apps/mongo-depl-765bbddfc5 1 1 1 8m46s
  • Access the app via the IP address of the minikube cluster. Get the IP address of the minikube cluster via minikube ip. If the IP address is 192.168.49.2, access it via http://192.168.49.2/.
  • When you access the app, it should look like this:
Output on the web browser

2. Project Structure

k8s-todo 
│ Makefile — file with commands for building the app and images
└───backend — NestJS app for backend services

└───frontend — React app for frontend

└───infra — YAML files to create Kubernetes resources

3. Infrastructure

Diagram showing Kubernetes resources
  • Let’s start with ingress definition first: infra/ingress-srv.yaml
    ingress routes the requests depending on the specified path
    — so if the request has the path 192.168.49.2/, it will redirect the request to frontend-srv because path: / means anything after the forward-slash except when there are other rules (check out the path for backend-srv).
    ingress-srv.yaml defines which router pattern belongs to which service and to what port the request should be sent to
    — for example, 192.168.49.2/api/todos will redirect the request to backend-srv at port 3001
    now what happens to the request? Here comes the service.
  • Services are defined in infra/backend-depl.yaml and infra/frontend-depl.yaml
    ingress sends the request to a Kubernetes service
    — a service allows pods to be accessible via the exposed ports
    port defines the port to which a request is sent to reach the pod; if a pod or other systems want to reach the pod, they need to use the defined port (except if there’s a nodePort which can be used too, but this project doesn’t use it)
    targetPort defines the port that the pod is listening to; for example, if a Node application is listening to 3001, the container where the Node application is deployed should also listen to 3001. Therefore, if we want to let the request reach the Node app, we should use 3001 as the targetPort
    — what happens after a pod receives the request? Let’s talk about deployment and then the pod
  • Deployments and pods are defined also in infra/backend-depl.yaml and infra/frontend-depl.yaml
    — A deployment contains a pod and dictates how many instances (i.e., replicas) of the pod will be created based on the image and what are the images to be containerized (i.e., put an image into a container — it’s like running a NodeJS app in a new server)
    — A pod may contain one or more containers but usually just one
    — A container is like a VM (to put it simply but they’re different) mounted with a snapshot (what we call an image)
    — An image contains the application files; it’s usually ready-made system files for use.
  • When you run make build-app, it does the following:
    — creates the Kubernetes resources inside the infra folder; resources are the pods, services, and deployments
    — pulls up the images from the Docker Hub (alvinlucillo/k8stodo-frontend:latest and alvinlucillo/k8stodo-backend:latest); these images are built before I released this article so you can make use of it. However, you’re free to create your own based on the frontend and backend of this repo (use the commands I created in the Make file)

--

--

Alvin Lucillo
Nullify
Editor for

Software engineer, writer, self-taught pianist, and a lifelong learner