Deploying Node.js Apps to a Kubernetes Cluster

Node.js is a popular, open source development platform that lets you run JavaScript code on the server side. Node is useful for developing applications that require a persistent connection from the browser to the server and is often used for real-time applications and single-page applications.

Node.js runs on a dedicated HTTP server and is designed to use a single thread in one process at a time. Node.js applications are event-driven and calls are asynchronous by default. Node.js applications do not follow the traditional process of receiving a request, processing it and returning a response. Instead, Node uses an event stack to handle incoming requests, pooling requests and dispatching them one after the other without waiting for a response.

What is Kubernetes?

Kubernetes is an open source platform for managing Linux containers in private, public and hybrid cloud environments. Many DevOps teams use Kubernetes to manage their microservices architecture, where each microservice is encapsulated in one or more containers. Kubernetes also supports a GitOps development model in which all changes to a Kubernetes cluster are fully automated and managed in source control.

Containers and Kubernetes can be deployed on-premises and in all public clouds, making them an ideal platform for cloud-native applications that need to scale quickly and must be portable between environments.

Application developers, IT system administrators and DevOps engineers use Kubernetes to automatically deploy, scale, maintain, schedule and operate multiple application containers on a cluster of nodes. Containers run on a shared operating system but are isolated from each other.

Kubernetes makes it possible to create a cluster of hosts running Linux containers and manage large numbers of containers running on those hosts. 

Running Node.js on Kubernetes

You can deploy any application on Kubernetes, but there are certain things you can do to adapt your applications to a containerized environment. Here is how to make a Node.js application better-suited to Kubernetes:

  • Ensure the application is stateless—Make sure you do not store state in external locations such as databases, queues and in-memory caches. It is also preferable not to enable user file upload. This will let you run multiple instances simultaneously and scale horizontally as needed. Kubernetes does support stateful applications, but this increases the complexity of deployment.
  • Get all configuration from environment variables—Do not hardcode environment-dependent variables in the application. In particular, do not store secrets in plaintext—use the Kubernetes secrets mechanism or a dedicated secrets management solution.
  • Run autonomously—When it runs successfully, the application should immediately accept requests or handle other types of loads without requiring initialization processes. Kubernetes will automatically detect errors in the application or its host and try to fix them; for example, by restarting the pod or moving it to another node.
  • Implement graceful shutdown—Kubernetes might shut down your pod at any time (depending on your configuration). To avoid downtime, ensure that if your application receives a shutdown signal, it can complete any work in progress and gracefully shut down without interrupting user requests or corrupting data.
  • Implement error handling—Error handling and logging is important to be able to troubleshoot issues in a complex Kubernetes environment. Pay special attention to application and container exit codes—these must be handled reasonably to allow Kubernetes to manage the container life cycle.
  • Centralized logging—In Kubernetes, there are many application instances running on different hosts, and it can be complex to set up Kubernetes persistent volumes. Assume that all logs will be erased when an application instance or pod shuts down. The solution is to have a cloud-native logging and monitoring solution that continuously collects and saves data from application instances.

Quick Tutorial: Kubernetes Deployment of Node.js Applications

To deploy a Node.js application to Docker or Kubernetes, you first need to build a container image. To do this, you usually start with an existing image and add additional layers of functionality as needed.

When building Node.js applications, the community provides several official Docker images to help you get started. These images provide Node.js binaries on top of an existing Linux distribution (typically Debian or Alpine). You can start from these official images and add your application as an additional layer.

Step One: Choose Your Image

There are three types of official Node.js images:

  • Full Debian-based image—Contains all the core components needed to build and test Node.js applications.
  • Slim Debian-based image—Contains only the minimal packages needed to run pre-built Node.js applications.
  • Alpine-based images—Offers a minimal container size.

Step Two: Define a Dockerfile

Starting from your base image, you will use a Dockerfile to build a custom image containing your application. The following is the simplest possible Dockerfile, which copies your Node.js application (app.js) into an official Node.js container image.

FROM node : 12.13.1

EXPOSE 3000

COPY app.js .

CMD node app.js

Step Three: Build the image

To build an image from the Dockerfile, place the file in the directory containing your application code and run the following command:

docker build -t myImage:new

This will create a Docker image named myImage with the label new based on the contents of the current directory.

Step Four: Push the Image to a Registry

To make this image usable by Kubernetes, you need to publish it to the registry. You can then run and test your application in Docker or Kubernetes.

Step Five: Define Kubernetes Deployment

The typical way to deploy an application to Kubernetes is via a Deployment object. Here is an example of a Deployment object that deploys two replicas of the container image we defined previously: myImage with the label new.

apiVersion: apps/v1

kind: Deployment

metadata:

    name: myImage

    labels:

        app: myImage

spec:

    replicas: 2

    selector:

        matchLabels:

            app: myImage

    template:

        metadata:

            labels:

                app: myImage

        spec:

            containers:

           —name: myImage

               image: myImage:new

               imagePullPolicy: Never

               args:

Once this YAML is in place, you can run this command to create the Deployment in your Kubernetes cluster:

kubectl apply -f deployment.yaml

Step Six: Define Service and Ingress

The last step is to allow other components and users to access your application. To this end, you will need to define two more Kubernetes objects: A Service and an Ingress. These are outside the scope of this article, but you can learn more about them in the Kubernetes documentation. 

You deploy the Service and Ingress using these commands:

kubectl apply -f service.yaml

kubectl apply -f ingress.yaml

Once you understand the basics of Kubernetes deployment, a more convenient way to package and deploy your application is by using Helm charts. Helm is a Kubernetes package manager, and a Helm chart is a template that includes all the components we saw above: A Deployment, Service and Ingress, and ensures they are deployed correctly in one step. 

Conclusion

In this article, I explained the basics of Kubernetes and showed basic requirements for deploying Node.js web applications to a Kubernetes cluster. I showed how to deploy your first Node.js application to Kubernetes in six steps:

  1. Choose a container image to run Node.js
  2. Define the Dockerfile
  3. Build the image
  4. Push it to a registry
  5. Define the Kubernetes Deployment object
  6. Define a Service and Ingress to enable clients to access your application

I hope this will be useful as you learn to deploy your Node.js projects to a modern cloud-native environment.

https://containerjournal.com/features/deploying-node-js-apps-to-a-kubernetes-cluster/