NodeJS Docker Deployment Process

How To Package NodeJS, Build & Deploy A Docker Container To Digital Ocean

Manny
5 min readNov 28, 2018

Creating Simple NodeJS JWT API

For the purposes of this tutorial we’re going to use this GitHub repository of an existing Simple ExpressJS API. Note there is no database associated with this backend to demonstrate how to package micro-service by itself.

We’re start by clone the repository, installing the packages locally to test that it works.

Cloning & Running

git clone https://github.com/codingwithmanny/simple-expressjs-api;# install dependencies.
# make sure you have node installed on your computer
cd simple-expressjs-api;npm install;# start servernpm start;

Testing Application

Next we’re going to use Postman to load the files to test the endpoints.

Postman Collection & Environment Files

Import the collection file into Postman.

Import from the top left.

Import the environment file into Postman.

Import from the settings icon in the top right.

While the NodeJS server is running on port 5000, go through the 3 endpoints.

POST request to get an issued token.
GET request to validate the token.
GET request with token in header to get user details.

We can now see that the API works locally. Let’s now try and build a custom container and test it with the code.

Testing It Within A Container

Let’s go back to Terminal, stop the server, and remove the node modules because they will be different for Mac OS and Linux.

# ctrl + c - to stop the serverrm -rf node_modules;

Now let’s create a new Docker container based on an Alpine image.

We’ll mount the local folder to mnt of the repository and expose the port 5000.

docker run -it -p 5000:5000 -v $PWD:/mnt alpine /bin/sh

While we’re in the container let’s install nodejs:

apk update;
apk add nodejs;
apk add npm;
apk --no-cache add --virtual builds-deps build-base python;
# double check the node version
node -v;
# [Expected Output]
# v8.11.4
# check the version
npm -v;
# [Expected Output]
# 5.6.0

Switch to the folder, install the dependencies, start the server, and test it with Postman again.

# switch
cd /mnt;
# install
npm install;
# start
npm start;
# [Expected Output]
# Listening on port 5000.

(Repeat the steps for Postman to validate that the endpoints are working)

Now that it’s working let’s stop it container and delete it and focus on creating a Dockerfile next the step, but first:

# ctrl + p then ctrl + q to exit the containerdocker rm -f {name-of-container};

Creating Dockerfile

Next steps is to take those same steps we worked on to package the container as one isolated container that automatically starts up.

First let’s create the new file, while in the repository:

# create Dockerfile
touch Dockerfile

Using the editor of your choice, open up the Dockerfile and let’s being to add the necessary commands:

# base image
FROM alpine
# port exposed
EXPOSE 5000
# copy current directory into /mnt
COPY . /mnt
# install dependencies
RUN apk update && \
apk add nodejs && \
apk add npm && \
apk add build-base && \
apk add python && \
cd mnt && \
npm install;
# command executed at run
CMD ["/bin/sh", "-c", "cd /mnt; npm start;"]

Building

Now that we have our Dockerfile, let’s run the application.

# from within the root of the repository directory
docker build . -t nodejsdocker

Testing It By Running

Let’s run the application to test it.

docker run -it -d -p 5000:5000 --name mynodejs nodejsdocker

Test that the main url is running:

curl localhost:5000# [Expected Output]
# {"time":1543375771016}%

Let’s also run a newman test, with the requirement that nodejs is installed on the host computer:

# install newman globally
npm i -g newman;
# switch to postman files in repo
cd postman;
# run test
newman run ExpressJS\ API.postman_collection.json -e ExpressJS\ API.postman_env.json;

Sweet satisfaction…

Let’s kill the docker container now:

docker rm -f mynodejs;

Optimizing

Add a .dockerignore to your repository will speed up things:

# .dockerignore
node_modules

Optimizing The Dockerfile

# base image
FROM alpine
# port exposed
EXPOSE 5000
# copy current directory into /mnt
COPY . /mnt
# install dependencies
RUN apk update && \
apk add nodejs && \
apk add npm && \
apk add build-base && \
apk add python && \
cd mnt && \
npm install && \
apk del build-base && \
apk del python && \
apk del npm;
# command executed at run
CMD ["/bin/sh", "-c", "cd /mnt; node index.js;"]

Build it again with:

docker build . -t /nodejsdocker

You’ll see the file size was brought down from 248MB to 44.5MB

docker images

Saving The Image

Now that we build the image, let’s push it to Docker Hub. Assuming you have an account, you’ll need to retag your

docker tag nodejsdocker {docker-hub-user}/nodejsdocker

Once that’s done, let’s push it to Docker Hub.

docker push {docker-hub-user}/nodejsdocker

Testing It Completely Locally

To see that it worked correctly, let’s remove all trace of the docker image from our host computer.

docker rm -f mynodejs; # or the container name
docker rmi -f nodejsdocker;
docker rmi -f {docker-hub-user}/nodejsdocker;

Now run the container as if it were pulled directly from Docker Hub.

docker run -it -d -p 5000:5000 --name mynodejs {docker-hub-user}/nodejsdocker;# test to see if the api endpoints are running
curl localhost:5000;
# [Expected Output]
# {"time":1543379495303}%

Deploying To Digital Ocean

Coincidentally you’ll be performing that exact same steps to run on Digital Ocean. The only difference is wether or not you want to install Docker yourself or use the existing Docker instance from DO and you just need to login to access the image if it’s a private repo.

If you got value from this, and/or if you think this can be improved, please let me know in the comments.

Please share it on twitter 🐦 or other social media platforms. Thanks again for reading. 🙏

Please also follow me on twitter: @codingwithmanny and instagram at @codingwithmanny.

--

--

Manny

DevRel Engineer @ Berachain | Prev Polygon | Ankr & Web Application / Full Stack Developer