Dockerizing a NodeJS Application in 2021

Houssam Yahiaoui
codeburst
Published in
5 min readJun 30, 2017

--

Notices: This article was written back in 2017, still the very same steps are still valid now.

Well, it is not a lie, knowing how to really and fully Dockerizing an app despite your stack is one of the hottest things nowadays, now we’re in 2017 means that we’ve tons of tutorials explaining what’s the deal behind Docker and the story of containers, images, and the ecosystem in general, so in this tutorial, we’ll try to get down to it and see how we can Dockerize a Nodejs application in today's fast-moving world!

1 — The Need to YARN

Feel the Yarn!

If you’re a NodeJS developer you would recognize by now the idea of package managers, plus the whole benefits that come from it, but for some folks out there, NPM (Nobody really knows the true meaning of the letters) is just a bit slow for their internet connection, so Yarn saw the light, with its parallel download mechanism that can speed up thing, also securing the semver of any dependency/sub dependency your application work with.

Also, Yarn was one of the most requested features in the past because simply Yarn is not bundled with the Node setup and you will need to install it, also to keep the lovely added value that it offers, from the lock file to the super-powerful cache, it was clear in the docker-node official image provided by the folk behind NodeJS over numerous issues, but now things are slightly different!

2 — Energizing the image!

In your development project, create a Dockerfile (Yeah it’s called the Dockerfile without any extensions) and copy down the following file :

Now, let’s digest the 10 steps we’ve above in the Dockerfile.

Step 1: Picking the base Image (Mandatory) :

Picking the right image is the first thing to do over any Dockerfile, within this image is you will find a complete Operating system bundled with NodeJS, Npm and you guessed it right, Yarn as well, knowing that you can create your application using a normal Ubuntu image, or any image for that matter, but you will handle personally all the heavy lifting and downloading and installing all your stack within it, which I personally consider a tedious thing to do.

PS: you have tons of node-based images that you could use but from personal experience, I found some issues working on images based on Alpine (another Linux distro like Ubuntu) while installing some System Level packages, the image I’m using above is Debian wheezy.

Step 2: Adding some Metadata (optional):

While this step is not what you call mandatory, but it’s always nice to document your work and add some metadata, and I guess it’s quite descriptive, also you might find in older Dockerfile online something like :

Maintainer Name <email>

This syntax is deprecated, and the Label one is the newly proposed one, so in case you found any of that over Github, be the good guy and submit a new PR 😉 !

Step 3: Creating & Specifying the WORKDIR (Mandatory) :

In this step, we will create the working directory & tell Docker where we want our application to live, also where your Docker command will be executed at, this is important because you really don’t want Docker to automatically create it for you unless it’s intentionally.

Step 4: COPY Command :

In the scope of NodeJS application it’s kinda mandatory, because what we will do, is simply copying the Package.json, npm-shrinkwrap.json to our working directory, means if you’ve specified the WORKDIR over past step it will be automatically copied inside working directory.

PS: You can normally copy the files using the following command:

COPY package.json npm-shrinkwrap.json* /usr/app/appName

But, apparently, it’s kinda “best practices” to use the bracket way, so it’s good to work and use best practices since the beginning of your Docker Journey.

Step 5: Specifying the Node Environment Variable :

In this step, things will start looking like a normal NodeJS Application, since you can add your environment variable (not all of them, the most needed one) in our case, it’s “production”, but you can specify the “Staging”, and other flow you’re or your company are using to you needs.

Step 6: Some custom global setup! (optional)

In this step, and at least for my temporal use case I’m installing forever a simple cli utility that allows us to keep our server alive and running, well forever.

PS: Using forever might be interesting for staging but you might think of another solution once you go to production, something like PM2.

Step 7: Installing some dependencies :

In Step, we’re logging inside our working directory, and yeah you guessed it right, we’re installing our dependencies, you might say where he can find the package.json, well remember step 3 and 4, yarn will install your dependencies based on the package.json file you’ve uploaded early on, and install everything within it in a really fast way!

Step 8: Copying EVERYTHING (Mandatory)!

This step is essential, it’s where we’re going to copy everything from our local working directory to our Docker Image, but bear in mind, that Docker has something called .dockerignore in this file you can specify all the files, the directory that you DON’T usually want to be bundled within, means files and documents like your local dependencies, READMEs

Step 9: EXPOSING the Port (Mandatory)!

In this step, we’re informing Docker that this application will be going be to listen on port 1337, but when we launch it won’t simply work (we will see how to fix this in a minute).

Step 10: Adding some BASHs (Optional)!

In this step, we’re simply ADDing another special file, this file will simply going to have some custom BASH command for my needs, them I’m giving the file some authorization and simply executing it but in your case, you probably won’t going to do that so simply replace step 10 with this :

CMD [“forever”, “app.js”]

This command will simply be going to use our installed forever utility and excuse our beloved application.

Simple hien !

Now, you might wonder, how I can launch my application!, this is an excellent question, so let’s see the normal step to do so :

1 — Grab yourself a Terminal/CMD.

2 — Build your image with the following command:

docker build -t <image-name> .

3 — Run your image locally :

docker run --rm -it -p 1337:1337 <image-name>:latest

PS: the: latest suffix is what we call a flag, it going to be present automatically whenever you build your application, and it’s like anything in Docker, it’s customizable.

In the step above, we’re running our Docker instance in an interactive mode, which means it’s going to be verbose, and we’re going to see our below stdout logs.

Let’s back up everything we just saw :

1 — You can run it locally.
2 — You can bundle everything within the same container, which means your dependencies, custom system packages.
3 — You can configure it, to run whether as a normal image or executable.
4 — You want to professionally handle it? lean some Bash Scripting.
5 — You can run within it programs that do not exist in your personal development machine.

Show the love, heart it/share it if you liked it!

PEACE ⚡️ !

--

--