Building Nodejs Microservice - A Cloud-Native Approach - Part 1
Tags: node
Published: 2021-01-19 12:45:56

If you're reading this article, I assume that you know how to build an Application using Nodejs. few may know how to build the frontend as well.

Well, I have a task for you before getting into this article. Build me a `Project Management Application` using Nodejs.

![](https://media.giphy.com/media/3o7527pa7qs9kCG78A/giphy-downsized.gif)

if you implement something like this,

[![](https://cloudnweb.dev/static/206e9fe74a71e57e3892fd73c583fd63/e3189/monolith.png)](https://cloudnweb.dev/static/206e9fe74a71e57e3892fd73c583fd63/cbe7f/monolith.png)

Then, you are not probably in 2021. Don't get me wrong. there is nothing wrong with above approach. i still works well for lot of application requirements.

But, let me tell you how it's going to make difference in application development. Let's say that you implement your project using Monolith Architecture and your application starts to evolve, continous iteration and building features on top of it.

At some point of it, you will start to feel uncomfortable and your code become unmaintainable. it makes the application overly complicated and other developers fears to build features or maintain it.

Here are the side effects of it,

*   Application gets overly complicated and hard to maintain
*   Adaptation for new technology will not be an option.
*   Implementing a new feature become a time consuming process etc.

That's when the Microservices comes into picture,

![](https://media.giphy.com/media/QArnd5QDqR7lyS8t4G/giphy-downsized.gif)

Let's implement the sample application architecture in microservice way,

[![](https://cloudnweb.dev/static/9402ed5203055b9bec8511eef182ea89/e3189/microservices.png)](https://cloudnweb.dev/static/9402ed5203055b9bec8511eef182ea89/80990/microservices.png)

Now, the application modules are decomposed into isolates microservices. each services will be independent with it's own code and dependancy.

So far, we have seen the difference between Monolith and Microservices. If you watch it carefully, i introduced an another term called `Cloud Native Approach` .

Well, let's see what does it mean by that,

### What is a Cloud-Native Application?

Cloud-Native is a modern way to build a Large scale system. it is a systematic approach to build a large system that can change rapidly with zero downtime and resilient at the same time.

There are a lot of open source applications that evolved over time to make it possible. tools such as `Docker`, `Kubernetes`, `Helm` , `Prometheus` and `gRPC` helps us to build such applications.

If somebody asks you, what does it mean by `Cloud Native Application Development` ?. just tell them that,

> Cloud native application development is an approach to building and deploying applications quickly, while improving the quality and reducing risk.it is just a way to build scalable, resilient and fault-tolerant applications with zero down-time in deployment.

To learn more about Cloud-native Application, check this awesome [docs](https://docs.microsoft.com/en-us/dotnet/architecture/cloud-native/introduction) from Microsoft

Cloud-based approach follow [12 factor methodology](https://12factor.net/) which describes set of principle and best practices that we need to follow while building a cloud-native application.

Here we are going to implement two simple micro-services which are `project` and `task` services. it will be a simple Express application.

The main purpose of this article is to make you understand how to build a Microservices in cloud-native approach. we will not be focusing on the business logic of each microservices.

Once you understand the outer layer. you can easily build your own business logic inside each service.

> Note: I assume that you have basic knowledge on Docker and Kubernetes. if you are new to those topics. i suggest you to check [these](https://cloudnweb.dev/tag/kubernetes) articles

Enough of the theory. let's implement a Nodejs Microservices and see it in action

![](https://media.giphy.com/media/sOSZ8OB5yyFfAMlxw8/giphy.gif)

### Project Service

Create a simple Express Application with the basic boilerplate code.
```
const express = require("express");

const bodyParser = require("body-parser");

app.use(bodyParser.json());

app.use(bodyParser.urlencoded({ extended: false }));

app.get("/project", (req, res) => {

 res.send("Welcome to ProjectService");

 console.log("Listening on PORT 4500");
```
Now, let's dockerize our Nodejs Application. create a `Dockerfile` inside your `project` service directory.

Don't forgot to add `.dockerignore` inside your root directory

### Task Service

Do the same for Task service,

1.  Create a Simple Express Application
2.  Dockerize your `task` service
3.  add `.dockerginore` inside your task service
```
const express = require("express");

const bodyParser = require("body-parser");

app.use(bodyParser.json());

app.use(bodyParser.urlencoded({ extended: false }));

app.get("/task", (req, res) => {

 res.send("Welcome to TaskService");

 console.log("Listening on PORT 4501");
```
Once you complete the docker configuration. you can build docker images using the command,

[![](https://cloudnweb.dev/static/d4831a06079390d47848ffb631deddf0/e3189/01.png)](https://cloudnweb.dev/static/d4831a06079390d47848ffb631deddf0/a8a6f/01.png)

[![](https://cloudnweb.dev/static/57fdbca874452e241ee8ea1b7575dca7/e3189/02.png)](https://cloudnweb.dev/static/57fdbca874452e241ee8ea1b7575dca7/229ad/02.png)

Now, we have our containerized microservices. if you run the docker container, each containers will be running in a separate ports.

[![](https://cloudnweb.dev/static/b548e6ef56d5ae9334b3be7b2ed5cc75/e3189/containerized-application.png)](https://cloudnweb.dev/static/b548e6ef56d5ae9334b3be7b2ed5cc75/d10dd/containerized-application.png)

But wait, we want our application to run in a single port. right?

[![](https://cloudnweb.dev/static/8f568965f3982ebde57ba42da5e5402b/e3189/containerized-app-updated.png)](https://cloudnweb.dev/static/8f568965f3982ebde57ba42da5e5402b/d10dd/containerized-app-updated.png)

To achieve this, we need `kubernetes`. Kubernetes is a orchestration tool that helps us to manage our docker containers and load balance between them etc.

### Infrastructure

Here, we want to route our the request to appropriate docker containers. let's implement kubernetes on top of our Nodejs Microservices.

Note: If you're new to Kubernetes, i recommend you to check [this](https://cloudnweb.dev/2020/07/kubernetes-nodejs-developers) article to understand the basics of kubernetes

To explain it simpler, Kubernetes requires `Service` and `Deployment` to manage the pods inside Nodes.

Let's create `Service` and `Deployment` config for each micro-services,
```
 image: ganeshmani009/projectservice

 name: project-srv-clusterip
```
Let's break down `Deoployment` config to understand it better,
```
 image: ganeshmani009/projectservice
```
`metadata` name specifies the name of deployment.

`matchLabels` creates `Pod` with the specified name here. After that we create `Pod` with template
```
 image: ganeshmani009/projectservice

### Kubernetes Services

 name: project-srv-clusterip
```
Here, we specify the kind as `Service`, then metadata name as `project-srv-clusterip`.

`selector` specifies which pod that needs to be mapped with Service. here, it's mentioned as `projects`.

`port` specifies the incoming port on the request. `targetPort` specifies the port to which the request needs to be forwarded to.
```
### Task Service Infrastructure

 image: ganeshmani009/taskservice

 name: task-clusterip-srv
```
To run the kubernetes cluster, we can use the command `kubectl apply -f`

[![](https://cloudnweb.dev/static/8980af5e030e255604fc6a2163d8502c/e3189/03.png)](https://cloudnweb.dev/static/8980af5e030e255604fc6a2163d8502c/8ae78/03.png)

[![](https://cloudnweb.dev/static/8b3df83e72d14f3877e501e35ee000cc/e3189/04.png)](https://cloudnweb.dev/static/8b3df83e72d14f3877e501e35ee000cc/525d3/04.png)

One final thing that we need to set in kubernetes configuration is a controller to handle the request from outside world to kubernetes clusters. because, we can't access the kuberetes clusters directly.

To do that, we need `ingress control` to access the clusters. let's set `ingress` controller,

create `ingress-srv.yml` inside the `infra` directory and add the following config,
```
apiVersion: networking.k8s.io/v1beta1

 kubernetes.io/ingress.class: nginx

 serviceName: project-srv-clusterip

 serviceName: task-clusterip-srv
```
Here, we use `nginx` as ingress controller. there are [other](https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/#additional-controllers) controller that you can use in our kubernetes applications.
```
apiVersion: networking.k8s.io/v1beta1

 kubernetes.io/ingress.class: nginx
```
On the above code, we specify `apiVersion` and king of configuration. then, we set some meta-data. important thing to note here is the `annotation` which is `nginx` here. if we want any other controller, our configuration will change based on that.
```
 serviceName: project-srv-clusterip

 serviceName: task-clusterip-srv
```
After that, we have rules which specifies `host` and `http paths` mainly. host is your application DNS. here, we specify our local server domain set in `[hosts](https://setapp.com/how-to/edit-mac-hosts-file)` config file.

Two important things to note here is,

1.  `path` : it specifies the path that we want to access our particular microservices. let's say that we want to access our Project Microservice in route `/project-api` we need to specify it in the path.
2.  `backend` : it specifies the kubernetes cluster that we want to access in the specified route.

Now, to run the ingress controller. we need to use the following command,

[![](https://cloudnweb.dev/static/b427d3926b86500c36ba51228d2b8e57/e3189/05.png)](https://cloudnweb.dev/static/b427d3926b86500c36ba51228d2b8e57/84ee5/05.png)

Finally, That complete our Microservice Configuration and setup.

![](https://media.giphy.com/media/4xpB3eE00FfBm/giphy-downsized.gif)

Let's access our microservice application routes in the browser and see whether it works or not,

[![](https://cloudnweb.dev/static/3a08cd735f1ab3dfb8f24a6df669359a/e3189/06.png)](https://cloudnweb.dev/static/3a08cd735f1ab3dfb8f24a6df669359a/8b70b/06.png)

[![](https://cloudnweb.dev/static/a2f2a47a7c1387904781d9e1d322495d/e3189/07.png)](https://cloudnweb.dev/static/a2f2a47a7c1387904781d9e1d322495d/8d68c/07.png)

It works as we expected. Now, we can build many microservices by following the same process and implement our business logics inside the microservices.

complete source can be found [here](https://github.com/ganeshmani/simple-nodejs-microservices)