Skip to main content

How to Build a Docker Container

In this article, I'm going to show you how to create a NodeJS Web server and turn it into a Docker container.  These instructions were written for a Mac, but can easily be adapted to other operating systems.

Step 1: Install NodeJS

The first step is to install NodeJS on your computer. You can download the latest version of NodeJS from the official website at https://nodejs.org/. Follow the installation instructions provided for your operating system.

Step 2: Create a project folder

Once NodeJS is installed, create a new project folder where you will store your web server code. You can create a new folder using your operating system's file explorer or the command line. Open the command line and navigate to the location where you want to create the folder. Use the following command to create a new folder and change the current directory to it:

mkdir my-web-server
cd my-web-server

Step 3: Initialize the project

Initialize the new NodeJS project using the following command:

npm init -y

This will create a package.json file in your project folder that will store your project dependencies and other important information.  

The -y parameter is to skip over a series of questions.  For this example, we can just use the defaults.

Step 4: Install Express

Express is a popular NodeJS framework that simplifies the process of creating web applications. Install it using the following command:

npm install express --save

The command downloads the Express package and saves it as a dependency to the package.json file.

Step 5: Create the server

Create a new file called server.js in your project folder. This file will contain the code for your web server. Add the following code to create a simple Express server and save it:

/**
* Author: Mitch Allen
* https://scriptable.com
* https://mitchallen.com
*/

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

// Requires launch via npm start to set value
const VERSION = process.env.npm_package_version;

app.get('/', (req, res) => {
res.send('Hello World!');
});

const server = app.listen(port, () => {
console.log(`version: ${VERSION}`)
console.log(`Server listening on port ${port}`);
});

process.on('SIGINT', () => {
console.debug('\nSIGINT signal received: closing HTTP server')
server.close(() => {
console.debug('HTTP server closed')
})
process.exit()
})

process.on('SIGTERM', () => {
console.debug('\nSIGTERM signal received: closing HTTP server')
server.close(() => {
console.debug('HTTP server closed')
})
process.exit()
})

This code imports the Express library, creates a new application, sets the port to 3000, and creates a route for the root URL that responds with "Hello World!".

The SIGINT handler shuts down the server if the user presses Ctrl-C.

The SIGTERM handler shuts down the server if it's terminated by the docker stop command which will be shown later in this article.

Step 6: Start the server

To start the server, run the following command in your project folder:

npm start

This will start the server and display a message in the console indicating that the server is listening on port 3000.

Press Ctrl-C in the terminal window and note how the SIGINT handler is called to shut down the server.

Step 7: Test the server

Run the server if it isn't running already:

npm start

Open a web browser and go to http://localhost:3000. You should see a message that says "Hello World!".

Now stop the server by pressing Ctrl-C so we can turn it into a Docker container.

Step 8: Install Docker

Docker is a popular tool for containerizing applications, allowing developers to package and deploy their applications in a portable and efficient manner. In this section, we will go through the steps required to turn the simple NodeJS web server example we created above into a Docker container.

The first step is to install Docker on your computer. You can download the latest version of Docker from the official website here:

https://www.docker.com/products/docker-desktop.

Follow the installation instructions provided for your operating system.

Step 9: Create a Dockerfile

The next step is to create a Dockerfile in your project folder. A Dockerfile is a set of instructions that tells Docker how to build your container. Create a new file - and it must be called Dockerfile - in your project folder and add the following content and save it:

# Use an official Node.js runtime as a parent image
FROM node:21.5-alpine

# Set the working directory to /app
WORKDIR /app

# Copy package.json and package-lock.json to the container
COPY package*.json ./

# Install dependencies
RUN npm install

# Copy the rest of the application code to the container
COPY . .

# Set the container's default command to start the server
CMD ["npm", "start"]

# Expose port 3000
EXPOSE 3000

This Dockerfile does the following:

  • starts with an official NodeJS image
  • sets the working directory to /app
  • copies the package.json and package-lock.json files to the container
  • installs the dependencies
  • copies the rest of the application code
  • sets the default command to start the server
  • exposes port 3000.

Step 10: Build the Docker image

To build the Docker image, run the following command in your project folder:

docker build . -t my-web-server 

This command tells Docker to build an image with the tag "my-web-server" using the Dockerfile in the current directory. The dot (.) specifies the build context, which is the current directory.

Step 11: Run the Docker container

To run the Docker container, run the following command:

docker run -p 3000:3000 --name test-server my-web-server

This command tells Docker to run a container from the "my-web-server" image and map port 3000 on the host to port 3000 in the container.  It also gives the container a name so we can refer to it later with other commands.

This command starts the server and makes it accessible at http://localhost:3000.

Step 12: Test the container server

Open a web browser and go to http://localhost:3000. Just like before you should see a message that says "Hello World!".  But this time it is coming from the server running in the container.

Step 13: List the container

Open up another command window and run the following:

docker ps

You should see a listing for your container which includes the image name (my-web-server), the ports (0.0.0.0:3000->3000/tcp), and the name (test-server).

Step 14: Stop the container

You can stop the container by using its name.

In a second command window run this:

docker stop test-server

Note that the SIGTERM handler is called to gracefully shut down the server.

If you run docker ps again you will see the container is now gone.

If you want to start it up again and you haven't removed it, you can use this command:

docker start test-server

Just be aware that it is now running in the background, which you can prove by browsing http://localhost:3000 again.

Now stop the container again so that it can be removed in the next step.

Step 15: Remove the container

You can remove the container by using its name.

In a second command window run this:

docker rm test-server

Step 16: Remove the image

You can list the images on your machine using the docker images command. But it may be a long list.  To just see your server, you can use grep like this:

docker images | grep my-web-server

To remove the image you can use the docker rmi (remove image) command, like this:

 docker rmi my-web-server

Step 17. Understanding the run command

If you execute the docker run command twice in a row, you will get an error the second time.  That's because the docker run command should really be called the docker create and run command.  It creates the container first, then runs it.  So you will get an error because the container has already been created.

You don't have to completely remove the container and the image to restart the server.  If you just stop it, you can restart it like this:

docker start test-server

Step 18. Combine commands

It takes two steps to build and run a container. It also takes three steps to clean up and remove a container.  Repeatedly creating and deleting a container for testing can be tedious.  So you can combine the steps like this:

To build, create and run the container using one line, combine the build and run commands like this:

docker build . -t my-web-server && docker run -p 3000:3000 --name test-server my-web-server

You can stop the container and remove it along with the image in one line like this:

docker stop test-server && docker rm test-server && docker rmi my-web-server

In a terminal window on some operating systems, you can use the up arrow key to find and run previous commands.  So for testing, you can just keep scrolling back up to repeatedly create and delete the images and the container.

Conclusion

Congratulations! You have turned a simple NodeJS web server example into a Docker container. From here, you can continue to add functionality to your server and deploy it to various environments using Docker.

You can find an example here:

References

  • Docker - [1]