NestJS Kubernetes Deployment | Part 2: Deployment

hüseyin nurbaki
5 min readOct 1, 2021

Deploying NestJS applications on the Kubernetes Cluster series is divided into two main and two follow-up stories.
Part 1: Containerizing a NestJS application with Docker
Part 2: Kubernetes Deployment
Part 3: Bonus: Ingress Configuration
Part 4: Bonus: Kubernetes CronJob — NestJS

In this story, two Kubernetes deployment YAML files will be covered. The first one is very basic, the second one is a little spiced up. Deployment specs are shallowly explained. NestJS image generated in the previous part will be consumed. Current Kubernetes version: v1.21.4

See original documentation for more about kubernetes deployments.
Follow
here if you don’t already have a Kubernetes cluster or tools such as “kubectl”.

Photo by Daniel Tuttle on Unsplash

Groundwork ⚒️

$ docker tag demo hhaluk/demo:0.0.1
$ docker push hhaluk/demo:0.0.1

If you’d like to use the image you’ve built on your local machine instead of downloading it from a remote repository, you can convert the
imagePullPolicy: Always section to imagePullPolicy: IfNotPresent in the following YAML files and skip pushing your image.

Create a namespace in your Kubernetes cluster if you don’t have already.
$ kubectl create ns beta

Create Your deployment.yaml file 🔧

The following deployment file includes the minimum configuration to deploy your application. Replace hhaluk/demo:0.0.1 with your image to test yours.

Use the following command to create/update your deployment:

$ kubectl apply -f deployment.yaml

See Troubleshooting/Notes at the end of the article

A Deployment defines the desired state of the application and provides declarative updates for Pods and ReplicaSets.

A service object is used to access pods. Pods are ephemeral, can be created and destroyed dynamically. Each pod gets an IP address. Kubernetes handles the discovery on its own. Accessing pods over a service sweeps the need of tracking the change of pods. Services use selectors to route requests.

After you confirm your app is up and running, it's time to access your application. Run the following command to test your service locally.

$ kubectl port-forward svc/demo-svc 8000:8000

Now the service is accessible over http://localhost:8000
This means requests made to your localhost’s port 8000 will be directed to the port of the service. Service will forward it to the pod and finally, it is routed to port 3000 of the container inside the pod.

Now you must have seen the “hello world!”

hello.png

This is the minimum configuration to get started. See next section to benefit more 🦾

Spice it up! 🌶️

There are some new specs added to the same deployment. These are few minimum good practices to follow.
Start with defining a new HTTP GET /health endpoint inside your app. (Demo app is provided at the end)

The strategy field specifies the strategy used to replace old Pods with new ones. The RollingUpdate field gives more control over deployment. maxUnavailable specifies the maximum number of Pods that can be unavailable during the update process. The maxSurge field specifies the maximum number of Pods that can be created over the desired number of Pods. (read more)

Resource request allows the scheduler to be able to decide which node to place your pod. The kubelet also reserves at least the request amount of that system resource specifically for that container to use. If your pod requires more resources, It will be placed inside a node that is more sufficient compared to other nodes.
The resource limit is the upper resource limit of a pod. Kubelet prevents pods from exceeding the specified limit. (read more)

Kubelet uses Readiness Probe to check if the application is ready to start accepting traffic, Liveness Probe to know when to restart a container. (/health endpoint in this case)
The periodSeconds field specifies that the kubelet should perform a liveness probe every 5 seconds. The initialDelaySeconds field tells the kubelet that it should wait 5 seconds before performing the first probe. (read more)

Use the following command to create/update your deployment:

$ kubectl apply -f deployment.yaml

Once your app is up and running, expose your service locally again with the following command:
$ kubectl port-forward svc/demo-svc 8000:8000

ta-da

Bonus Command 🤑

Manually scale up your application with the following command:
(see scale.png)

$ kubectl scale — current-replicas=1 — replicas=2 deployment/<DEPLOYMENT_NAME>

scale.png

Troubleshooting/Notes 🔫

This article focuses on simple and sustainable Kubernetes Deployments. These commands and deployment files can cover a lot of needs.
Configuring the specs mentioned in the second deployment yaml file is always good practice to follow. Resource limits can protect the cluster against potential leaks or drains. One thing to consider, if you do not know how much resource limit you should set, not setting or setting generous amount until discovering thee optimal can be a better approach. You wouldn’t want to live a case such as drowning the app while there is plenty of resources. Defining an optimal limit requires metrics of real-life consumptions. (There will be a specific story about defining appropriate resource limits later)

Don’t forget to build your image after adding the health endpoint.

Clean up: $ kubectl delete -f deployment.yaml
Obtaining Service PoLogs: Use the following command to obtain your pod’s logs. (see logs.png)
$ kubectl get pods
$ kubectl logs — follow <POD_NAME>

logs.png

Thank you for reading. Feel free to email me if you have any questions or suggestions.
Cheers! 🎉

--

--