Pravar Agrawal Technology & Travel

Node JS on K8s

Bootstraping your application on Kubernetes has never been easy, with so many tutorials available online. As long as we can package your application along with all the dependencies in a container, we can very well deploy it and run it inside a Kubernetes cluster. Let’s see how to run a simple hello world application written in Node JS as Kubernetes deployment.

As part of this, we will be creating a simple web application written in Node JS serving on port 3000. All the code which we will be using in this post can be obtained from this link. The deployment of Node JS application will have around 10 replicas(can be lower as well). We will also be creating a service of type NodePort so as to expose it later and access it locally. Let’s get started then.

Firstly, if we take a look at the deployment manifest,

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nodejs-deployment
  labels:
    app: nodeJs
spec:
  replicas: 10
  selector:
    matchLabels:
      app: nodeJs
  template:
    metadata:
      labels:
        app: nodeJs
    spec:
      containers:
      - name: hello-world-app
        image: pravarag/nodejs-test:latest
        ports:
        - containerPort: 3000
        resources:
          limits:
            cpu: 500m
            memory: 500Mi 
          requests:
            cpu: 5m
            memory: 5Mi
      priorityClassName: high-priority-class

Like I mentioned earlier, it has 10 replicas and uses my custom docker image hosted at pravarag/nodejs-test. We are making the application server running at port 3000 of the pod and giving few requests and limits so that we can test the autoscaling of pods later. Also, we have a priorityClassName defined, which I’ll explain at the end. And below is how the Dockerfile looks:

FROM node:12

WORKDIR /usr/src/app

COPY package*.json ./

RUN npm install

COPY . .

CMD ["node", "server.js"]

As we can see, it’s a basic node based server with required npm dependencies packaged into a container. Now, let’s take a look at the service file of our K8s deployment:

apiVersion: v1
kind: Service
metadata:
  name: nodejs-service
spec:
  selector:
    app: nodeJs
  ports:
    - protocol: TCP
      port: 3000
      targetPort: 3000
  type: NodePort

Here, we have defined a service of type NodePort for our deployment for the application port 3000. Now, with NodePort, we will be able to see a service running on the same port for each node which is created using NAT. Also, we will be able to access the service from outside the cluster using NodeIP:NodePort.

Let’s deploy these two in our K8s cluster running on GKE with 2 nodes and see the end result.

Deployment Status

Once deployed and service is created, we expose the service running inside K8s to our localhost port 3000 and then we can see the application running as below:

Application status

So, our Node JS based application is succesfully running inside our K8s cluster. Now, above in the deployment specs, I mentioned something called as PriorityClassName. While deploying the pods, I was testing for pod priority as well which is used to define when we want to priortize scheduling of our pods than any other pods. If somehow a pod cannot be scheduled, the kube-scheduler tries to evict(pre-empt) lower priority pods to make scheduling of pending Pod possible. Below’s how I have defined a PriorityClass:

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority-class
value: 1200000
preemptionPolicy: Never
globalDefault: false
description: "This priority class is for nodejs deployment pods"

Here, I’ve given a value of 1200000 to assign a higher priority to pods created as part of deployment defined earlier.

So, this was a very basic example of how to package a Hello World applicaion in Node JS and deploy it on a K8s cluster with all the specifications. More details on this are available here

References: