Using Node.js with Docker

I’ve looked at a few times, but I never had much of a need in my workflow. Now though, I’m more interested – we’ve got a few microservices that need to be running for our main application. They each are run using Node.js, and the “simple” method is to just open a new terminal window for each, starting them up manually. Of course, that’s something I forget to do until the main app’s tests show failures.

Docker Last week, after watching Scott Hanselman‘s Computer Stuff They Didn’t Teach You video #8: Containers? So What? Docker 101 Explained, I got to thinking about better ways to have those Node servers running.

The first thing I did was to put together a very simple Node Node.js logoapplication, using Express to serve static html files. To follow along, install Node.js, then open Powershell in Windows Terminal or your favorite console, and create a basic server app:

md node-docker
cd node-docker
node init
npm install express --save

This creates a simple Node application, which I then edited to serve files from a specific directory. In this case, I created a \content folder at the root of my drive and put a simple index.html file there.

var express = require('express');
var app = express();
var port = process.env.PORT || 5000;
var path = require('path');
var options = {
index: "index.html",
extensions: ['htm', 'html']
};

app.use('/', express.static('/content', options));

var server = app.listen(port, function () {
var host = server.address().address;
console.log('listening at http://%s:%s', host, port);
});

We can then start the little server using the command node server.js. Opening a browser to http://localhost:5000/ displays the index file from the content directory. That’s done via line 10, which basically maps the root directory of the webserver (‘/’) to the \content directory, and serves files from there. Control-C in the terminal will stop the server.

Next, install Docker. We’ll need to create a Dockerfile file containing the instructions on how to build an image.

FROM node:12
WORKDIR \temp\dockerwork
COPY package*.json ./
RUN npm install
COPY . .
CMD ["node","server.js"]

Docker’s build command will use that to build an image:

docker build --tag nodedock .

You can use docker images to see a list of all the images you have on your system, at this point you should see at least your newly-build nodedock app and an image with Node version 12 itself.

docker's IMAGES command

If you were to start up that image now, the app would run but it would have no data – if you watched the video I mentioned above and look at the Dockerfile, you know that the image only contains the app – not the \content directory. I created it this way on purpose, because I want to have a server app running but I want to be able to create data (html files) ouside the app. This means we need give our container (running image) access to our hard disk.

docker run -p 3000:5000 -v /c/content:/content --name nodedock --rm nodedock

This command
* runs our nodedock application,
* maps it’s port (-p) 5000 to docker’s port 3000,
* creates a volume (-v) that points to our c:\content directory and lets our Node app see it as /content
* and removes the container when we stop it running (--rm).

Docker Desktop

Now with that image running in our container, we can open a browser to http://localhost:3000/. We can open the Docker Desktop application to see all our containers, look at logs and other stats on each, and stop them when we don’t need them. If we don’t use the -rm flag, they’ll stick around.

Code behind this blog post can be found in this github repo.