Dockerizing your Node.js Applications
So you have Node apps, and you want to use them with Docker. In this tutorial, we will show you how to take your Node.js application and bake it into a Docker image. This is part one of a two part tutorial on Dockerizing your Node.js Infrastructure. If you are interested in a big picture talk on what Docker is, and why Node.js and Docker are a powerhouse couple, checkout my latest webinar recording from #NeedToNode.
Without further ado, let’s get started!
Starting from a Node.js Project
I’ve put together a sample project for this tutorial. If you don’t have a GitHub account, you will need one for this step. Head over to github.com/nodesource/docker-tutorial and make a copy of it for yourself by pressing the “fork” button, it should look like this:
This project is a simple Hello-World app with a single service dependency. You can open
app.js to find out which service, or wait for the magic to happen when we introduce
Once you have a clone of the project under your own name, go ahead and pull it down to your development machine using git.
$ git clone https://github.com/[your_user_name]/docker-tutorial.git … $ cd docker-tutorial $ ls app.js package.json
These examples will assume you are using terminal on a Unix style machine. If this assumption does not hold, you will need to translate the commands to your environment.
Now that we have the code, we can get right to work!
Dockerizing the app
We are going to start by creating a single file called
Dockerfile in the base of our project directory:
FROM nodesource/node:4.0 ADD package.json package.json RUN npm install ADD . . CMD ["node","app.js"]
Lets walk through this line by line to see what is happening here, and why.
Here, we are building our Docker image off of the latest 4.0 release of Node.js from NodeSource’s base Docker images. You always should to start your Dockerfile with a
FROM statement. This allows us to start building our Docker image from a point where Node.js and npm are already installed, along with most of the tools and libraries necessary to build most native modules in the npm ecosystem. If you wanted to build your project for another version of Node.js, or on a specific operating system, you can alter this line to reflect that like so:
For a full list of supported operating systems and Node.js versions, refer to the description at: https://hub.docker.com/r/nodesource/node/
Let’s take a look at the next three lines then.
ADD package.json package.json RUN npm install ADD . .
ADD command takes files and folders from your current working directory and puts them inside of the docker image at the location you specified. In this case, we are taking
package.json from your project and placing in the docker image as
RUN command will execute a shell command inside of a Docker container and will commit the changes to the image. In this case, we have our
package.json file present in the current working directory so we now want to run
npm install to download and install all of our dependencies.
After we have all of our dependencies installed, which takes quite a while compared to the rest of our Dockerfile due to the dependence on network, we will add the rest of our source files to the Image.
You may have noticed that we didn’t specify
/usr/src/app/when we specified where we wanted to place
package.jsonand the rest of the files in our working directory. That is because the base NodeSource docker image handled setting up our project directory inside of the Docker image using the
WORKDIRcommand. You don’t need to worry too much about that now, just know that you can specify relative paths inside of a
Dockerfileand, unless you override our
WORKDIRcommand, you will be working out of
And now for the magic. We specify the command to start our application using
CMD. This tells Docker how to run your application. With this completed file, we are now ready to build and run our shiny new Docker image.
After you finish this tutorial I recommend checking out the complete set of Dockerfile commands, using the fantastic reference provided by the Docker team: https://docs.docker.com/reference/builder/
Using your Docker Image
Now that we have defined our Docker image, let’s do something with it. We are going to start by building the image:
$ docker build -t "myapp" . Step 0 : FROM nodesource/node:4 ---> 813c5874eb90 Step 1 : ADD package.json package.json ---> 45726a0a7fb3 Removing intermediate container 78cd990108c5 Step 2 : RUN npm install ---> Running in 14a14e26e19f firstname.lastname@example.org node_modules/retry email@example.com node_modules/pg ├── firstname.lastname@example.org ├── email@example.com ├── firstname.lastname@example.org ├── email@example.com ├── firstname.lastname@example.org ├── email@example.com (firstname.lastname@example.org) └── email@example.com (firstname.lastname@example.org, email@example.com, firstname.lastname@example.org, email@example.com, firstname.lastname@example.org) ---> 4b6ede2c7fd7 Removing intermediate container 14a14e26e19f Step 3 : ADD . . ---> 0c5891f99c6c Removing intermediate container 5bdc6717ea4c Step 4 : CMD node app.js ---> Running in 5c75cb1759a7 ---> fec7c6f133a9 Removing intermediate container 5c75cb1759a7 Successfully built fec7c6f133a9
Your hashes, the alphanumeric strings that identify containers and images, will probably be different. As long as it says “Successfully built” on the last line, you are in good standing.
What we have done here is told the Docker daemon to build us an image using the
Dockerfile located in the current working directory (specified by
.), and to name it "myapp" (specified by
When this command successfully finishes running, we will have built an entire environment capable of running our node application. So now let’s run it!
$ docker run -it "myapp" Hello World
And there you have it! We just ran our first node application from inside a Docker container!
What did that command do? It told the Docker daemon to create and run a Docker container (specified by
run) built from the "myapp" image (specified by
"myapp"), and bind it to the current terminal’s stdin/stdout/stderr (specified by
-it). That last bit isn’t too important, just know that if you want your process to run in the current terminal window, just like you had started it from outside of a container, you need to use the
-it flags. If you want your container to run in the background (for example, a web server), you can use the
-d flag in their place.
Share it with the world (optional)
Now that we have our shiny new Docker image, we can share it with the world using the Docker registry. Head on over to hub.docker.com and set yourself up with an account. Then rebuild your Docker image, but use the new name:
$ docker build -t "your_user_name/myapp" .
Now, we can login and push our image to the docker registry.
$ docker login Username: your_user_name Password: Email: email@example.com Login Successful! $ docker push “your_user_name/myapp” …
Now head over to the Docker registry to find your brand new image, available for the world to use. Good job you!
You did it!
And that is all that is needed for putting your node app into a Docker image! But wait! There is more!
You may have noticed the long pause when running your node app inside of a Docker image. That is because our app depends on a database which isn’t present in our Docker image. In this tutorial, we showed you how you can Dockerize your Node.js apps. In the next tutorial, we will show you how you can Dockerize your Node.js infrastructure!