The full source code for this tutorial can be found here: TutorialEdge/Docker/node-docker
In this tutorial, we are going to be looking at how you can dockerize an existing NodeJS application and ultimately leverage the benefits of Docker. We’ll be creating a Docker image that will dynamically pick up changes to a NodeJS application and automatically recompile and rerun our application without having to rebuild and re-run our docker image.
Advantages of Docker
Docker offers a number of massive advantages and can drastically reduce the friction of deploying your application to multiple platforms with minimal fuss.
New developers can easily pull down Docker-ized applications and run them with a couple of commands on their local machine. Application developers explicitly state within the
Dockerfile everything that application needs in order to run.
Our NodeJS Application
We are going to start off with a fairly simple, 6-line NodeJS Express.JS application that will simply serve
Hello World! when it’s
/ endpoint is hit with a
The application will listen on port
3000 for any incoming requests and will map those requests against the corresponding route.
Create a new file called
app.js within a new
node-docker directory on your local machine. Once this is created, add the following:
As this uses the
express.js library, we’ll have to figure out a way of getting this into the Docker container that will be running our application.
If you are familiar with Node.js development, you’ll know that the standard practice for this is to declare that your application requires
express.js within the
package.json in your application’s directory. Create this now and add the following to the newly created file:
We can test if our application works locally by calling
npm installwithin our project directory and then subsequently calling
npm run start. You should then be able to navigate to
http://localhost:3000/and be greeted with
Hello World!in your browser.
Dockerizing our Application
The aim of the game here is to get a docker image that is as thin as possible in terms of size and is still able to provide our application with everything it needs in order to run successfully.
We’ll choose a fairly lightweight
alpine based image from which to base our own Docker image on top of.
Now, we’ve done two distinct
COPY commands within our
Dockerfile, and the reason for this is to reduce the time taken for us to continually rebuild our application.
Docker automatically caches the results of each individual command so that they don’t have to be fully run each time you wish to build a Docker image. By doing it this way, we can cache the results of our
npm install command so that every time we build our Docker image, it doesn’t constantly have to reinstall all our dependencies. This may not take a lot of time for this particular project, but for larger projects, this can become a massive time drain.
Building our Docker Image
Now that we have defined our
Dockerfile within our application’s directory, we can go about building our Docker image. We can do this by running the following
docker command within our terminal.
This will subsequently run through the 6 steps outlined within our
Dockerfile and build our complete Docker image.
Running our Docker Image
Once our Docker image has been successfully built, we can then go about running one or more Docker containers based off this image by running the following command:
This will start up a Docker container based off our
node-docker docker image and expose it on port
9000 on our machine. The
-d flag specifies that we wish to run this in a detached mode which means that the docker container will run in the background on our host machine.
It’s important to note that whilst our Node.js application may be listening for requests on port
3000within the code, by specifying
-p 9000:3000we essentially map any requests to port
9000from our host machine to the underlying docker container listening on port
Viewing running Docker Containers
In order to view all of the running containers on your local machine, type
docker ps. This should show our
node-docker container running and the ports that it’s listening to.
Automatically Picking up Changes
The first thing we’ll have to do in order for our running Docker container to pick up any changes is mount it to a directory on my host machine. We can achieve this by using the
-v flag and specifying the current directory of my application and mapping that to the
/app directory our application lives within in our docker container.
We can also install and use the
nodemon node_module in order to automatically watch for any changes to our source files and subsequently kick off our server with these incorporated changes.
nodemon is explicitly listed within our
package.json as a dependency, we can go ahead and rebuild our docker image:
We can then run this with the
-v flag as mentioned before like so:
If you now navigate to
http://localhost:9001 you should see your application up and running, if you then subsequently make any changes to the app, these changes will be picked up and automatically reran within our container! Awesome!
In this tutorial, we learned how to implement a docker container that perfectly wraps our NodeJS application. This Docker container is deployable anywhere that can run docker which is a massive advantage! No more worrying about the fact that “it works on my machine”.
If you found this tutorial useful then please feel free to let me know in the comments section below or on twitter: @elliot_f.