Docker and NodeJS: Getting Started
Tags: docker, container, node
Published: 2018-04-12 19:17:40

---
title: Docker and NodeJS: Getting Started
published: true
description: Let's Dockerize a simple NodeJS application
tags: docker, container, node
cover_image: https://thepracticaldev.s3.amazonaws.com/i/y3ofc0var1ijfbe1wzvo.jpg
---

## Introduction

Lately, I spent a lot of time in private blockchain's world. When you are learning a new technology like this one, you come across certain concepts or principles that you have to understand in order to move on. Docker and containers seems to be one of them right now for me. So, in a good old *let's write about what I learn* fashion, I'm trying to explain what Docker does and how I'm getting started with it.

## Containers?

Docker is a *platform* for developers to develop and deploy applications with *containers*. Docker didn't invent containers or containerization, but popularised the concept, so they are sometimes used to describe the same thing.

Containers are launched by running an *image*. An image is an executable that explains everything the application needs to run, and where/how to find them. A container is a running instance of an image. This way of doing things takes less resources than Virtual Machines (VM) that provides a full "virtual" operating system, which represents more resources than most applications need. By containerizing your application and its dependencies, differences in OS distributions and underlying infrastructure are abstracted away.

## Docker and NodeJS

Enough theory, let's see how we could use Docker to create an image for a NodeJS application.

First, install Docker by following the instructions <a href='https://docs.docker.com/install/'>here</a>. Once this is done, run `docker --version` in your terminal. You should have something like:

`Docker version 17.12.0-ce, build c97c6d6`

If you want to make sure everything is working, you can run: `docker run hello-world`. This will pull the *hello-world* image for you and launch a container.

You can see a list of the images you downloaded with `docker image ls`.

You can see a list of running containers with `docker container ls`, or you can have all the containers with `docker container ls --all`. Remember than containers are instances of the images you downloaded.

So, if you run the *hello-world* image, assuming you didn't have any containers running before, you will see one container in this list. If you run *hello-world* 5 times, you will have 5 containers ( instances of the *hello-world* image ).

*Note*: To stop containers, run `docker kill $(docker ps -q)`. You will still see these containers with ``docker container ls --all`. To remove them completely, run `docker rm $(docker ps -a -q)`.

### The NodeJS application

Let's do something very simple. An express app with 2 routes that renders 2 html pages. Create a new directory called express-app:

`mkdir express-app && cd express-app`

Run `npm init` with the defaults. Then, run `npm install express --save`.

Create 3 files: *index.js*, *index.html*, *about.html*.

- *index.js*

```javascript
const express = require('express')
const app = express()

app.get('/', ( req, res ) => {
	res.sendFile(`${__dirname}/index.html`)
})

app.get('/about', (req, res) => {
	res.sendFile(`${__dirname}/about.html`)
})

app.listen(3000, () => {
	console.log('Listening on port 3000!')
})
```

Create an express app, 2 routes for our html files and listen on port 3000.

- *index.html*

```html
<html>
	<body>
		<h1>Hello Docker from index</h1>
	</body>
</html>
```

- *about.html*

```html
<html>
	<body>
		<h1>About page</h1>
	</body>
</html>
```

Good, our app is done. If you run `node index.js`, you will see our html pages on localhost:3000/ and localhost:3000/about.

### Dockerfile

To define the environment inside your container, we will use a *Dockerfile*. This is a list of instructions that tells Docker what it must do to create the image we want.

Create a Dockerfile in your directory with `touch Dockerfile`:

```

FROM node:carbon

WORKDIR /usr/src/app

COPY package*.json ./

RUN npm install

COPY . .

EXPOSE 3000

CMD ["node", "index.js"]

```

What's happening here? The first line indicates that we want to use the latest node version to build our image. This is the image we start from. *node:carbon* being the latest Long Term Support version available.

The second line creates a directory to hold our application's code inside the image.

The third and fourth line copy the package.json and run the `npm install` command. The first line gives us node.js and npm. So we install our dependencies, in this case, express.js only. Note that we will **NOT** copy the /node_modules file.

The **COPY** instruction bundles our app inside the Docker image, so our html files and index.js file in our case.

The **EXPOSE** instruction exposes the 3000 port that our app uses.

Finally, the **CMD** instruction specifies which command needs to be run for our app to start.

### Build

Everything is now ready, we can build the app.

Run `docker build -t node-app .`

The *-t* tag allows you to specify a friendly name to your Docker image. You should see something like this in your terminal:

``` 
Sending build context to Docker daemon   21.5kB
Step 1/7 : FROM node:carbon
 ---> 41a1f5b81103
Step 2/7 : WORKDIR /usr/src/app
 ---> Using cache
 ---> ffe57744035c
Step 3/7 : COPY package*.json ./
 ---> Using cache
 ---> c094297a56c2
Step 4/7 : RUN npm install
 ---> Using cache
 ---> 148ba6bb6f25
Step 5/7 : COPY . .
 ---> Using cache
 ---> 0f3f6d8f42fc
Step 6/7 : EXPOSE 3000
 ---> Using cache
 ---> 15d9ee5bda9b
Step 7/7 : CMD ["node", "index.js"]
 ---> Using cache
 ---> 154d4cd7e768
Successfully built 154d4cd7e768
Successfully tagged node-app:latest

```

Now, if you run `docker image ls`. You will see your *node-app* in the list.

### Launch the container(s)

We can now launch our containers. Run `docker run -p 8080:3000 -d node-app`

The *-d* flag runs the app in detached mode. *-p 8080:3000* redirects a public port  to a private port. 8080 being the private port, 3000 the public port we exported.

Go to localhost:8080 and your app is running!

Now, run `docker run -p 10000:3000 -d node-app`, then `docker run -p 4000:3000 -d node-app`.

Open localhost:10000 and localhost:4000 and see that you have three different instances of your node-app image running at the same time! To make sure of it, you can run `docker container ls` and see your 3 containers running the same image on different ports.

Well, that was a quick introduction to Docker. Have fun!

*Edit:* I forgot to mention it and I should have. You should create a *.dockerignore* file and add *node_modules* in it to tell Docker you do not want this folder to be copied, since we copy the *package.json* file and run `npm install`. It will work if you omit it, but it makes more sense to have it ;)