NodeJS Docker Deployment Process
How To Package NodeJS, Build & Deploy A Docker Container To Digital Ocean
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 computercd 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.
Import the collection file into Postman.
Import the environment file into Postman.
While the NodeJS server is running on port 5000, go through the 3 endpoints.
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.