Subscribe to get my new tutorials in your inbox.

Run a Node Express.js server using Docker – Masterclass

Run a Node Express.js server using Docker - Masterclass

Hello Guys, I hope you are doing well. So in today’s article series of Learn By Doing (#LBD), we will be creating a simple Node Express.js server and then run it using Docker.

So this will be a 2 part series. The first part which is this one, we will run our Node Express.js server on our localhost using Docker. In part 2 we will move to the cloud. We will run the same server on an AWS EC2 instance using Docker of course. The first part that we will complete in this article will eventually lead to the second part. So it is important to follow along. Alright, let’s get started then.

Let’s write our Node Express.js server

Start with an empty folder which is our project folder. You can call it anything you like. For the sake of this example let’s name it my-simple-server. Now from the project root run the following command to create a package.json file. Our project is a Node application and we will be using NPM packages, so the package.json is the entry point.

npm init

This will take you through a series of questions as shown in the screenshot below. You can answer them and continue by pressing Enter or keep pressing Enter until you are done.

How to Run a Node Express.js server using Docker

Once done it will create a package.json file inside your project.

Create your package.json file

Now install Express.js. Its an NPM module available from the NPM registry.

yarn add express

I am using Yarn since I prefer it over npm commands. Once the yarn command is finished running you will have express (and all its dependencies) installed inside node_modules. Your package.json will also be updated with the dependency.

"dependencies": {
    "express": "^4.17.1"
}

Now that everything is set up, we can go ahead and write our server. Create a server.js file inside your project root.

touch server.js

This creates an empty server.js file as shown below,

Create your Node server.js file

Copy the code below and then paste it inside server.js file.

const express = require('express');
const app = express();

app.get('/', (req, res) => {
    res.send('Server is running');
});

app.listen(5000, () => {
    console.log('Server started at 5000');
});

Let me explain what we have written inside server.js file. So, we start by importing the express module. ExpressJS is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications. Using ExpressJS we can quickly bootstrap an HTTP web server. Alright, now in the second line we create an instance of express server. Then we define a GET path/route for our root URL. So when we hit localhost:5000 we should get a response from the server. Finally, we start our server and listen to port 5000 for incoming requests.

Now, run the server

node server.js 

You should see the log printed in your terminal. This launches our Express server.

Run your Node Express.js server

Now go ahead and open http://localhost:5000/ in your browser. You should see the response below.

Open your Node Express.js application in browser

This completes our first section of the tutorial. By now you should have a running server that can listen on port 5000. In case you have any issues, follow the steps again and see if you have any differences in your implementation. Most often or not it will be a typo šŸ™‚

Now let’s move our focus to Docker.

Why Docker?

Good question! So for you guys who are hearing about Docker for the first time, Docker is a container technology that helps you to deploy applications. It can be any application – a Node server application, a Database, a PHP application, a Java application, etc. Guys who are ware of Docker and has worked with it, can skip this section and move to the next one.

Why use Docker?

Let me come back to Docker. A Docker container is a standard unit of software that packages up code and all its dependencies so the application runs quickly and reliably from one computing environment to another. 

Imagine, we have to deploy our Node Express server application onto different environments. For example, I develop my express server on my local computer using Node 10. So I test everything and it works fine. Now, I need to deploy it on a QA box which is running Node 9. After that, I need to deploy my application on a staging server which runs Node 11. And then I go to production. All the way, I see that there are differences in the Node versions being used by different environments. This can be a big problem, isn’t it? While the application works on my computer, it can break when deployed onto another box.

running our Node application without Docker

This is where Docker comes in. If I bootstrap my Node Express server inside a Docker container running Node 10, then I can deploy the Docker container on all the environments and launch my Node express server. I need not worry about the system and version differences. Docker container creates an isolated environment for my application to run.

Running our Node Express.js server using Docker

Install Docker

Now that we understand why Docker is important, go ahead and install Docker on your computer. Go to Docker’s official site and download Docker desktop. Install it as per the installation instructions. I am not going to that as this will make our article very very long and boring.

Once installed you will now have access to the Docker CLI (command line interface). You do not need to install the CLI separately. It comes with Docker desktop. Now you have access to all the docker commands inside your terminal.

Before starting with the CLI go ahead and create a Docker account. Sign up on this page and then come back to the article.

Once you have your Docker account, head over to the terminal and run the following command

docker login

It will ask for your username and password. Enter them and submit. Now you are logged in to your Docker account from the terminal. This will allow you to push and pull Docker images onto Docker hub. We will talk about this later. Now, lets move on.

Create a Dockerfile

So, the next step is to create a Docker image or our container that will encapsulate our Node Express server. And we start by writing a Dockerfile. A Dockerfile is a set of instructions to Docker that specifies what goes inside a Docker image and informs about its environment. Let’s create a Dockerfile.

Run this command from your project root.

touch Dockerfile

This should create an empty Dockerfile. Pls, note there is no extension to the file.

Create a Dockerfile

Now, let’s write some Docker instructions. Open the Dockerfile in your editor and paste the code below.

# We build from an official Node image from Docker
FROM node:10

# Create app directory
# This will create /app folder inside the image
# Everything from here will be copied to /app
WORKDIR /app

# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
COPY package*.json ./

# Install all dependencies
# This will create a node_modules folder inside docker image
RUN npm install

# Copy our source code into the image
COPY . ./

#Expose the port that our Node Express server will run
EXPOSE 5000

# Define the runtime command
# This will execute when we run our docker image
CMD ["node", "server.js"]

The instructions above have been explained with comments inside it. But let me touch base on two important things.

The first line says,

FROM node:10

What this means is that Docker will install NodeJS version 10 inside my docker image. From where does it find it? – Docker has already hosted NodeJS versions in their official repository of images known as Docker Hub. It is much similar to the NPM registry. Just so that by typing npm install express we were able to install express, similarly Docker will install Node 10.

Now, the next important line that I want to focus on is

EXPOSE 5000

This instructs the Docker image to expose the port that my Node Express server will be running on. If you open server.js file, you will notice that my server listens on port 5000. Docker image is an isolated container. My Node Express server is running inside this container on port 5000. Now, Port 5000 has to be exposed to the outside world, i.e outside the Docker daemon for the world to access our server. Refer to the image below for a visualization.

Expose port from Docker

We will talk about this more when we run our Docker image. Hang on for now! Let’s move onto the next step.

Create a .dockerignore file

From the root of your project run this command,

touch .dockerignore

This creates an empty .dockerignore file. This is similar to .gitignore. This will instruct Docker not to copy the resources mentioned inside it.

Create a .dockerignore file

I already have a template below. Copy and paste it inside your .dockerignore file.

.git
.gitignore
node_modules
npm-debug.log
Dockerfile*
docker-compose*
README.md
LICENSE
.vscode

Alright, onto the next step now.

Let’s Build our Docker image/container

From the root of the project run the command below,

docker build -t your_docker_username/my-simple-server:v1.0.0 .

This command reads the Dockerfile and creates a Docker image. Let’s understand the command.

  • docker build: command to build a docker image
  • -t specifies a tag. v1.0.0 in this case. This flag lets you tag your image so it’s easier to find later using the docker images command
  • your_docker_username/my-simple-server: this is the container name scoped by your docker username. Do not forget to replace it with yours.
  • Final dot – this means the current folder. Basically our project folder

Once it runs successfully, you can check your image by using the command below,

docker images

This will list all the docker images on your computer. As you can see in the screenshot below, our Docker image has been created.

list of docker images

Now, our Docker container has all the necessary things bootstrapped inside it to run our Node Express.js server application.

By the end of all this, our Docker image will look something like this,

Docker image visualization

Now let’s run our Docker image/container and launch our server.

Run the Docker image

Use the command below to run the image,

docker run -p 4000:5000 your_docker_username/my-simple-server:v1.0.0

So, it does two things.

First, it goes ahead and runs our Node Express.js server at port 5000. Mind you, the Node server is running inside the Docker container isolated from the environment outside it.

Secondly, the -p flag redirects a public port to a private port inside the container. So basically it maps 4000 to 5000.

Now, you can access your Node server at localhost:4000. Go ahead and try it.

Run a Node Express.js server using Docker

So we have been able to run our Node Express.js server using a Docker container.

What happens if you try to access localhost:5000? It’s not reachable, of course. Because 5000 is private to the Docker image. Refer to the image below to visualize.

Public to Private Port mapping in Docker Run a Node Express.js server using Docker

Run in the background or detached mode

docker run -p 4000:5000 -d your_docker_username/my-simple-server:v1.0.0

Did you notice the flag -d, that is what will run the image in background.

Stop the Docker image

Run the commands below to stop a container/image.

# Lists the currently running image
docker ps 

# Example Output
CONTAINER ID        IMAGE                              COMMAND                  CREATED             STATUS              PORTS                    NAMES
7294eb465c97        jsphkhan/my-simple-server:v1.0.0   "docker-entrypoint.sā€¦"   42 seconds ago      Up 41 seconds       0.0.0.0:4000->5000/tcp   magical_pare

And then stop it,

# stop the image by its ID
docker stop <Container ID>

# Example
docker stop 7294eb465c97

This will also stop our Node Express.js server. Now if you go and try to access localhost:4000 in the browser it will not be reachable.

Check the logs from inside the Docker image

If you want to check the logs of your Node Express.js server, use the command below,

# Print app output
$ docker logs <Container ID>

# Example
docker logs 7294eb465c97

Now you can see the console logs.

Push the Docker image to Docker Hub

Alright, so this is an important part of the whole Docker ecosystem and Docker Hub is a very important part of it.

Just like Github, you commit and push your changes to your repository. Later through CI/CD, you can deploy the code to a server. Similarly, you can push your Docker images to Docker Hub and later on, you can pull any image from the Hub and deploy and run it. No need to build the image every time.

First, let’s push our image. Use the command below,

docker push your_docker_username/my-simple-server:v1.0.0

This is self-explanatory. If you notice the command is very similar to git push. Now, your image should be available on Docker Hub. Refer the screenshot below,

Docker Hub Run a Node Express.js server using Docker

Pull Image from Docker Hub

Use the command below,

docker pull your_docker_username/my-simple-server:v1.0.0

This will basically download a copy of the docker image version. You can then run the image and launch your server. This will actually help us in our second part of this tutorial. We will pull this image inside an AWS EC2 instance and run our Node Express.js server using Docker inside the EC2 box. The second part will be ready soon.

Alright, so we have finally reached the end of this article and by now you should be able to run a Node server by using Docker. I will leave you with an assignment that you can try – Go ahead and create a ReactJS application and run it using Docker.

Code available on Github

The full example is available on my Github repo: https://github.com/jsphkhan/my-simple-server

Useful Docker commands for Beginners

I have a separate article on that which lists down all the useful Docker commands that you will need as a beginner. Check it out!

Conclusion

I hope this has been an interesting read for you guys, as much as it took me to write this entire article. Meanwhile, I am compiling the second part to this tutorial where we will deploy our simple server to Amazon AWS Cloud and learn something new along the way.

Till then, Cheers!


If you enjoyed this post and want similar articles to be delivered to your inbox directly, you can subscribe to my newsletters. I send out an email every two weeks with new articles, tips & tricks, news, free materials. No spamming, of course.


Write a Comment

Your email address will not be published. Required fields are marked *