Table of Contents
- 1. Introduction
- 2. Prerequisites
- 3. Objectives
- 4. Node.js application setup
- 5. Express packages setup
- 6. RESTful APIs implementation
- 7. Dockerizing the Express application
- 8. Setup YAML service to deploy Dockerized Node.js Express application
- 9. Deploying to Kubernetes service
- 10. The deployment dashboard
- 11. Accessing the application
- 12. Conclusion
In this tutorial, we will go over how to build RESTful APIs using the Node.js Express framework, test them locally using docker-compose. We will then proceed to deploy this application to the Kubernetes.
1. Introduction
Express is a backend development framework built on top of Node.js, it enables the implementation of the client-server architecture. With its flexibility, it allows for the customization of the API endpoints, consequently, fitting our needs.
2. Prerequisites
To follow along with this tutorial, you need the following:
- Node.js downloaded and installed in your local development environment.
- Basic knowledge in Node.js’ Express framework.
- RESTful APIs design.
- Basic knowledge in Docker
- Basic knowledge in kubernetes
3. Objectives
By the end of this article, you should be able to create a complete dynamic Express application and deploy it to the cloud using Docker.
4. Node.js application setup
Let’s start by importing required modules and create a running server:
//this node application is located in the index.js file const http = require("http"); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World\n'); }).listen(8000); console.log('Server started at http://127.0.0.1:8000/');
Now execute this application by running the command on the command line:
node index.js
Execution output:
The server started at http://127.0.0.1:8000/
5. Express packages setup
Add the following contents in your server.js
script:
const express = require('express'); const app = express(); const bodyParser = require('body-parser'); // import the student schema defined in the student.js file const Student = require('./models/student'); //register router middleware const router = express.Router(); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); const port = process.env.PORT || 8000; const config = require('./config'); const mongoose = require('mongoose'); mongoose.connect(config.db[app.settings.env]);
In the script above, we imported the Express package. Additionally, we imported packages that will aid in running our Express application and setting up a connection to the database.
Now that we have got a connection to the MongoDB database server, let’s define the model that we will use to get the list of students from a school database.
const mongoose = require('mongoose'); const Schema = mongoose.Schema; const StudentSchema = new Schema({ student_id: String, name: String, registration_number: String, course: String, year_of_study: Number, }, { timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' } }); module.exports = mongoose.model('Student', StudentSchema);
In the model above, we set up the student details we will be getting via our API.
6. RESTful APIs implementation
Now that we’ve set up our model and server file, in this section, let’s implement our RESTful APIs and deploy our application to the cloud.
router.get('/students/:student_id', function(request, response) { Student.findOne({student_id: request.params.student_id}, function(err, Student) { if (err) { response.status(500); response.setHeader('Content-Type', 'application/vnd.error+json'); response.json({ message: "An error occurred, unable to get student details"}); } else if (Student == null) { response.status(404); response.setHeader('Content-Type', 'application/vnd.error+json'); response.json({ message: "ProductQuantity not found for product_id "+request.params.student_id}); } else { response.status(200); response.setHeader('Content-Type', 'application/hal+json'); let student_resource = halson({ student_id: Student.student_id, name: Student.name, course: Student.course, year: Student.year_of_study, registration_number: Student.registration_number, created_at: Student.created_at }).addLink('self', '/students/'+Student.student_id) //response response.send(JSON.stringify(student_resource)); } }); }); // let's now register our routes app.use('/', router); // now start the server on port 8000 app.listen(port); console.log('Starting server on port ' + port);
7. Dockerizing the Express application
Now that we’ve defined our core application API logics, let’s proceed to our main aim of the tutorial, dockerizing your RESTful Node.js Express application.
This section assumes you have Docker up and running in your Ubuntu machine.
Let’s proceed and define the contents of the Dockerfile
to direct docker on how to build a container image of our Express application.
# the base image from which the app is built upon FROM node: latest # Runs the mkdire command to create /usr/src/app inside docker container RUN mkdir -p /usr/src/app # Sets the work directory to /usr/src/app WORKDIR /usr/src/app # Copies the contents of the current directory into the working directory inside the # docker container COPY . /usr/src/app # Exposes port 8000 outside the docker container EXPOSE 8000 # Runs the npm install command to install dependencies RUN npm install # Provides the command required to run the application CMD ["npm", "start"]
This Dockerfile
uses npm to install modules in our RESTful application. Let’s now proceed and set up the docker-compose configuration file that we’ll use to launch the Node.js Express application (including the MongoDB instance).
------------------------- # Service name student: # build in the current directory build: . # command to run the app command: npm start # Maps port 8000 inside docker container to port 8000 outside docker container ports: - "8000:8000" # linking the student to mongodb container links: - mongodb # env variables environment: - NODE_ENV=production - MONGODB_ADDRESS=mongodb # mongodb service mongodb: # pulling mongodb image image: mongo
8. Setup YAML service to deploy Dockerized Node.js Express application
Now that we’ve dockerized our application locally, the next step involves deploying the application to the cloud.
Let’s proceed and set up the service to deploy the app as shown below
//service.yaml file ----------------------------- services: inventory: git_url: git@github.com:myexample.git git_branch: main command: npm start build_root: . ports: - container: 8000 http: 80 https: 443 env_vars: NODE_ENV: production databases: - mongodb
Note, make sure you change your git URL in the above service.
You can now log in to your favorite cloud vendor to deploy your dockerized application.
Now that we have a Docker container image, we need to create a deployment file. In the root directory, create a new file called deployment.yaml
. This file will deploy the application to the Kubernetes engine.
Add the following snippets to the file:
apiVersion: v1 kind: Service metadata: name: rest-test-service spec: selector: app: rest-test-app ports: - protocol: "TCP" port: 3000 targetPort: 8000 type: LoadBalancer --- apiVersion: apps/v1 kind: Deployment metadata: name: rest-test-app spec: selector: matchLabels: app: rest-test-app replicas: 5 template: metadata: labels: app: rest-test-app spec: containers: - name: rest-test-app image: rest-test-app imagePullPolicy: IfNotPresent ports: - containerPort: 8000
The file has two parts:
Service
– The service acts as the load balancer. A load balancer is used to distribute requests to the various available servers.Deployment
will act as the intended application. The user request hits the load balancer, then the load balancer distributes the request by creating the number of replicas defined in thedeployment.yaml
file. For example, in our case, we have five replicas for scalability, meaning that we will have 5 instances running at a time.
The benefit of multiple replicas is that if an instance crashes, the other application instances continue running.
The deployment.yaml
file is connected to the Docker image created earlier, therefore to deploy the application to the Kubernetes cluster, we use the Docker image. The image will automatically create containers for the application when we deploy the application.
9. Deploying to Kubernetes service
We have dockerized our RESTful application, and now we need to deploy it to a Kubernetes engine.
Execute the command below in your terminal:
kubectl apply -f deployment.yaml
This command will deploy our service and application instances to the Kubernetes engine. After executing this command, we should be able to see that the rest-test-service
and the rest-test-app
are created successfully.
10. The deployment dashboard
Minikube and Kubernetes provide a dashboard to visualize the deployment. To see our deployment in that dashboard, execute the command below in your terminal.
minikube dashboard
We can see that our rest application was deployed and we can see the number of running instances. If a request is made, the load balancer distributes the number of hits the request had on the instances.
11. Accessing the application
We can access the application using the command below:
minikube start service: rest-test-service
12. Conclusion
In this tutorial, we’ve covered the key concepts of Node.js Express application RESTful APIs. We discussed how we can dockerize this application locally using Docker and deploy it to the Kubernetes.
Happy coding!