How to Dockerize an ExpressJS Application
Tags: docker, node, express
Published: 2019-05-31 00:02:43

## What this is
- This is a short example on how to Dockerize an ExpressJS application.
- This post also assumes you are working from a *NIX based OS such as Ubuntu 18.10

## What this is not
- This is not a thorough guide on Docker, NodeJS, ExpressJS, or any other technologies that may be used.
- This does not explain or walk you through the installation process of Docker or any technologies used.


---

## Create Directory
We need to create a directory. This is where we are going to place all of our Docker Images' files as well as our ExpressJS files.

```nix
foo@foo:~/path/to/current/directory$ mkdir node_docker_project
```

## Create Dockerfile
`CD` into the new directory and create a new file and name it `Dockerfile` without any extension name.

```nix
foo@foo:~/path/to/current/directory$ cd node_docker_project
foo@foo:~/node_docker_project$ touch Dockerfile
```

Place the next piece of code inside of the `Dockerfile`.

```docker
# Tell Docker to use the "node" Docker Image at version "10.15.3"
FROM node:10.15.3
# Create our containers WORKDIR and "node_modules" directory.
# Give the user:group "node" ownership of all files/directories in our containers WORKDIR
RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app
# Tell our container which directory to use as the WORKDIR
WORKDIR /home/node/app
# Copy over our local version of "package.json" and "package-lock.json" into our container
COPY package*.json ./
# Creates a user for our container
USER node
# Installs our NPM packages from the "package.json" file we moved from local in to our container
RUN npm install
# Tells our container who owns the copied content
COPY --chown=node:node . .
# Exposes the port "3000" from our container
# This is also how we can connect to our container from our host machine (the one you're reading this from now)
EXPOSE 3000
# An array of commands our container needs to run when we start it
CMD ["npm", "run", "start"]
```

## Create app.js
```javascript
const express = require('express')
const app = express()
app.get('/', (req, res) => {
  res.send('Hello, world!')
})
app.listen(3000, () => console.log('Server listening @ 3000'))
```

## Create package.json
Let's create our package.json file to hold our dependencies.

```nix
foo@foo:~/node_docker_project$ npm init -y
```

Then we need to install those dependencies.

```nix
foo@foo:~/node_docker_project$ npm i express
foo@foo:~/node_docker_project$ npm i --save-dev nodemon
```

We need Express as that is going to be the framework we are using for our server and we need Nodemon so that we can have automatic server restart by default. This will come in handy as you change files from local to the container. Without Nodemon, you would need to restart your container every time you make a change just to see the changes.

## Create our Docker Image
Think of a Docker Image as the recipe and a Docker Container as the meal. In order to eat the meal we need to cook it using a recipe.

```nix
foo@foo:~/node_docker_project$ docker build -t node_project
foo@foo:~/node_docker_project$ docker images
REPOSITORY     TAG      IMAGE ID     CREATED          SIZE
node_project   latest   3esadssa     10 Seconds Ago   908MB

foo@foo:~/node_docker_project$ docker run --name myNodeProject -v $(pwd):/home/node/app -d -p 3000:3000 node_project
foo@foo:~/node_docker_project$ docker ps
CONTAINER ID  IMAGE         COMMAND          CREATED
123klasdkj    node_project  "npm run start"  6 seconds ago

STATUS        PORTS                   NAMES
Up 4 seconds  0.0.0.0:3000->3000/tcp  myNodeProject
```

## Check your work
Now that we've created our container and it's up and running, we are able to connect to our container via the opened port(s). In our case we opened one port at 3000.

Open your browser and navigate to `http://localhost:3000` and you should be greeted with our `Hello, World!` message that we place in the `app.get('/' ...)` request in the `app.js` file we created earlier.

## Check that we can change the container files from our host machine
Go ahead and change the response text in our `app.js` file from `Hello, World!` to `Docker is amazing!`.

```javascript
const express = require('express')
const app = express()
app.get('/', (req, res) => {
  res.send('Docker is amazing!')  // change this line
})
app.listen(3000, () => console.log('Server listening @ 3000'))
```

Back in your browser, either refresh with `f5` or navigate back to `http://localhost:3000` and you should see the new response.

---

## Summary
The basics of Docker is actually pretty simple. All you need to do is:

- Get a Docker Image
- Create a Docker Container
- Connect to your container via the opened port(s)

---

## Resources
- [Clone this Docker Image from GitHub](https://github.com/bbenefield89/DockerizedExpress)

- [Learn the basics of Docker and more from Travery Media](https://www.youtube.com/watch?v=Kyx2PsuwomE)

- [Docker Hub (GitHub for Docker Images)](https://hub.docker.com/)