Build and Deploy a Node.js Microservices Application
Tags: node, microservices, docker, kubernetes
Published: 2022-11-16 05:49:16

When it comes to modern software development, microservices are one of the hottest trends. These small, standalone software services allow developers to build and deploy smaller code chunks that can be updated more frequently and respond faster to user needs. In addition, with microservices, teams can update individual services on their own schedule instead of waiting for a new version of the entire application or OS upgrade. Each service is also much smaller, making it easier to understand, test, document, and maintain. Moreover, microservices help you address any challenges that may arise during development.  

This tutorial, I'll explain what microservices are and how to deploy them using Harness CD. Harness is a continuous delivery platform. 

## What is a Microservice?
A microservice is a small, autonomous software service inside a larger application. Traditional monolithic applications are comprised of modules built as one piece in a single codebase. In a microservices-based architecture, services are designed as independent and modular pieces and can be deployed separately. Each microservice typically handles one specific business function and is built, deployed, and managed independently.

## Pre-requisites
- Free [Harness Continuous Delivery](https://app.harness.io/auth/#/signup/?module=cd&utm_source=internal&utm_medium=social&utm_campaign=community&utm_content=microservices-article-harness&utm_term=get-started) account 
- Access to a Kubernetes cluster. You can also use Minikube or Kind. 

## Tutorial
Let’s build a node.js microservice to know the distance between two zip codes. 

Create an app directory to store your application code and use the command `npm init -y` to initialize the project. Then, let’s add the main application code to the `server.js` file.

```
const express = require('express')
const app = express();
const port = process.env.PORT || 3002;
 
const routes = require('./api/routes');
routes(app);
app.listen(port, function() {
  console.log('Server started on port: ' + port);
});
```
Let’s define routes and controller logic. First, create a new folder by the name api inside your root folder to hold our routes and controller logic.

The complete project folder structure is below:

![project structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i8h8z4hhmn6v2u1s4x63.png)

Inside the api folder, create two files - `controller.js` and `routes.js`.

Add the following code to the `routes.js` file:

```
'use strict';
 
const controller = require('./controller');
 
module.exports = function(app) {
  app.route('/about')
      .get(controller.about);
  app.route('/distance/:zipcode1/:zipcode2')
      .get(controller.getDistance);
};
```
Add the following code to the `controller.js` file:

```
'use strict';
 
var properties = require('../package.json')
var distance = require('../service/distance');
 
var controllers = {
  about: function(req, res) {
      var aboutInfo = {
          name: properties.name,
          version: properties.version
      }
      res.json(aboutInfo);
  },
  getDistance: function(req, res) {
          distance.find(req, res, function(err, dist) {
              if (err)
                  res.send(err);
              res.json(dist);
          });
      },
};
 
module.exports = controllers;
```
Now, it is time to write some code to handle the external API. We will use zipcodeapi.com to calculate the distance between two locations with pin codes. Go to [http://www.zipcodeapi.com](http://www.zipcodeapi.com) and get the API key.

![API Key](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v11a2530yvqg5nlzdn8a.png)

Now, create a new folder inside the root folder and name it **service**. Inside the service folder, create a new file named `distance.js` and add the following code:

```
var request = require('request');
 
const apiKey = process.env.ZIPCODE_API_KEY || "DemoOnly00xM8GfwlIQE2Jf2FneBr1uZBPGCw3W8DzyZjKoPaVCRGamRCaclrpVR";
const zipCodeURL = 'https://www.zipcodeapi.com/rest/';
 
var distance = {
  find: function(req, res, next) {
      request(zipCodeURL + apiKey
              + '/distance.json/' + req.params.zipcode1 + '/'
              + req.params.zipcode2 + '/mile',
      function (error, response, body) {
          if (!error && response.statusCode == 200) {
              response = JSON.parse(body);
              res.send(response);
          } else {
              console.log(response.statusCode + response.body);
              res.send({distance: -1});
          }
      });
 
  }
};
 
module.exports = distance;
```
Now, go to the main folder (root) of the application and start the application by using the command `npm start`.
Go to your [http://localhost:3002/about](http://localhost:3002/about) and you should see the name of the folder and version.

![app running](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kty3daz046cbjn0lrwjj.png)

Next, check our next route i.e. distance. Go to [http://localhost:3000/distance/pincode1/pincode2](http://localhost:3000/distance/pincode1/pincode2).

Add pincode1 and pincode2, and you should see the distance between these two zip code areas.

An example is below,

![distance between locations](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zn041eakunh1slz021dm.png)

Try again to find the distance between two zip codes - 35004 and 86556.

![new distance](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kgjgeskapqdi6h735vqo.png)

So, we have successfully built a simple microservice to know the distance between two zip codes. 

### Deploy the Application Using Harness:
Harness is a modern software delivery platform that helps organizations easily deploy their applications. We will now see how we can deploy this application on Kubernetes using Harness. 

The first thing we need to do is to dockerize our application using a Dockerfile. Let’s write a simple **Dockerfile** for our application.

```
FROM node:14-alpine AS development
ENV NODE_ENV development
# Add a work directory
WORKDIR /app
# Cache and Install dependencies
COPY package.json .
RUN npm install
# Copy app files
COPY . .
# Expose port
EXPOSE 3002
# Start the app
CMD [ "npm", "start" ]
```
Using the below command, build the Docker image:
`docker build -t microservices-app .`

Run the Docker image with the following command:
`docker run -p 3000:3000 microservices-app`

Build the image again using DockerHub credentials:
`docker build -t DockerHub Username/microservices-app .`

Now, push the image to Docker Hub using the below command:
`docker push DockerHub Username/microservices-app`

![microservices app on docker hub](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ixys3ikotlpd7hkqtijq.png)

Now that we have pushed our application as an image to Docker Hub, we can deploy the application on Kubernetes using Harness CD module.

But before, we need to create Kubernetes manifest files deployment.yaml and service.yaml to deploy our application.
Let’s create `deployment.yaml` file.

```
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
  app: microservice-app
name: app-deployment
spec:
replicas: 2
selector:
  matchLabels:
    app: microservice-app
template:
  metadata:
    labels:
      app: microservice-app
  spec:
    containers:
    - image: pavansa/microservice-app
      name: app-deployment
      ports:
      - containerPort: 3000
```
Push the application code to a new GitHub repository.

Signup for the [Harness platform](https://app.harness.io/auth/#/signup/?module=cd&utm_source=internal&utm_medium=social&utm_campaign=community&utm_content=microservices-article-harness&utm_term=get-started) and opt for the CD (continuous delivery) module.

![CD Module](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iz2fo7rs8rjvbssqvpql.png)
Set up the required connectors, such as Docker Hub, GitHub etc. and the delegate.

![Harness connectors](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4jqebhpmocq5l7bwzg11.png)

The [Harness Delegate](https://docs.harness.io/article/h9tkwmkrm7-delegate-installation) is a tool you need to install and run on the target cluster (Kubernetes cluster in our case) to connect your artifacts, infrastructure, collaboration, verification and other providers with the Harness Manager. When you set up Harness for the first time, you install a Harness Delegate.

Configure a simple pipeline for your application. This is where you will define service, infrastructure, and execution type. 

A service represents what you are deploying, like a Kubernetes manifest and a Docker image of your microservice. Infrastructure tells Harness where you're going to deploy your application. Execution is how this stage deploys its service to its infrastructure.

![App deploy](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lbkvcsac9g5exx0umpv9.png)

Make sure you have configured everything properly, and save and run the pipeline to deploy your application onto Kubernetes. 

![application deployment pipeline](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r8x3zhoc91tj5wb2vv1b.png)You should see a successful deployment message.

![deployment successful](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wjcwa2cd26bwpexkxdkf.png)Congratulations! We successfully built a node.js microservice and deployed it on Kubernetes with the help of [Harness CD](https://harness.io/products/continuous-delivery?utm_source=devto&utm_medium=blog&utm_id=pavan). 

Ultimately, the pros and cons of using microservices will depend on your particular situation. However, in general, microservices are excellent for large and complex applications that need to scale. Therefore, they are often used in conjunction with containers and service-oriented architecture. On the other hand, microservices are not always valid for small applications. However, microservices are suitable for both large and small applications, and their usefulness depends on how they are implemented.

Microservices are the new trend in modern software development. They allow developers to build and deploy smaller, more independent code chunks that can be updated more frequently and respond better to user needs. While there are many different types of microservice architectures, we recommend that you choose a microservices architecture that makes sense for your business and technology stack.