21 Aug 2018
Dockerizing my Node.js Forge web app
Docker has been around for a couple of years already, it is a hot open source project that allows you to deploy your applications in containers adding a layer of abstraction. This Docker adaption is growing, and it is growing fast. If you want to learn more about what Docker is and what the benefits of it are, you can check these following resources.
In this post we will use the simple Tutorial application shared in the past with many of you. If you would like to go over the Node.js app I will recommend doing so since this will give you a good base to get started with Autodesk Forge platform. The app lets you authenticate, create buckets, upload files, translate files, use the Forge viewer to visualize the recently translated files. You can find the Tutorial here. Make sure you pick the Node.js server option since this post will be dedicated to Node.js in Docker.
Once we are ready with our Forge Node.js application we will start with the process of dockerizing our app. The goal of this example is to show you how to get a Node.js application into a Docker container. The guide is intended for development, and not for a production deployment.
Definitions
Here are a few names used on this tutorial (from Docker Glossary):
- Docker image: An Image is an ordered collection of root filesystem changes and the corresponding execution parameters for use within a container runtime. An image typically contains a union of layered filesystems stacked on top of each other. An image does not have state and it never changes. Docker images are the basis of containers.
- Docker container: A Docker container consists of: a docker image, an execution environment, a standard set of instructions. The concept is borrowed from Shipping Containers, which define a standard to ship goods globally. Docker defines a standard to ship software. A container is a runtime instance of a docker image.
Prerequisites
The guide also assumes you have:
- Docker installation
- Nodejs app (e.g. you can use this tutorial code)
Time to complete: 2 hours
Creating a Dockerfile
The Dockerfile defines the container and actions to be performed on initialization.
Note: A Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image. Using docker build users can create an automated build that executes several command-line instructions in succession. This page describes the commands you can use in a Dockerfile .
Assuming you have a project similar to the tutorial, at the root of your project, create an empty file called Dockerfile, from your terminal you can type the following:
Touch Dockerfile
Open the recently created Dockerfile in your favorite text editor
The first thing we need to do is define from what image we want to build from. For the base image, we will use the latest LTS version node:carbon this is the BUILD part.
Note: If you want to find out more about what code name “carbon” is you can read more about it here. Be aware that specifying the version of Node is also another option.
FROM node:carbon AS build
Next, we will create an app directory and set its location to it.
WORKDIR /usr/src/app
Now, we will copy the package.json and package-lock.json into the container work directory.
ADD package.json .
ADD package-lock.json .
We will install the app and copy the app code to the container image.
RUN npm install
ADD . .
We are now done with the BUILD part and we will start cleaning up the dockerization (is that even a word??) process.
FROM node:carbon
We will copy the app from the BUILD stage
COPY --from=build /usr/src/app .
We will create ENV variables since our Node.js app uses them in the config.js file. The value of our keys will be passed at the time of run time of our container.
ENV FORGE_CLIENT_ID=default
ENV FORGE_CLIENT_SECRET=default
We will use the same port as our original application, but we still need to define it.
EXPOSE 3000
Last but not least, define the command to run your app using CMD which defines your runtime. Here we will use the basic npm start which will run node server.js to start your server:
CMD [ "npm", "start" ]
Your Dockerfile should now look like this.
# start with image that has Node.js, this is BUILD part
FROM node:carbon AS build
# Create app directory, set this as work directory
WORKDIR /usr/src/app
# copy package.json AND package-lock.json into container work dir
ADD package.json .
ADD package-lock.json .
# install the app and copy app code to container image
RUN npm install
ADD . .
# clean the stuff up, this is part 2
FROM node:carbon
# Copy app from BUILD stage
COPY --from=build /usr/src/app .
# use the value to set the ENV var default
ENV FORGE_CLIENT_ID=default
# use the value to set the ENV var default
ENV FORGE_CLIENT_SECRET=default
# define default port
EXPOSE 3000
# run container
CMD [ "npm", "start" ]
Create a .dockerignore file in the same directory as your Dockerfile with following content:
node_modules
npm-debug.log
Tip: if you are using git, just duplicate your .gitignore and add .git folder (usually hidden). This will prevent your local modules and debug logs from being copied onto your Docker image and possibly overwriting modules installed within your image.
Building your image
Go to the directory that has your Dockerfile
and run the following command to build the Docker image. The -t
flag lets you tag your image so it's easier to find later using the docker images
command:
# build image
docker build -t autodesk-forge-docker .
At the terminal, at the first time, it will start downloading the node:carbon. Then you should see steps 1 through 11, similar to the following:
Sending build context to Docker daemon 10.92MB
Step 1/11 : FROM node:carbon AS build
---> ed145ef978c4
Step 2/11 : WORKDIR /usr/src/app
---> Using cache
---> 4b0cf8d43623
Step 3/11 : ADD package*.json .
---> Using cache
---> 8c894ea8ae9b
Step 4/11 : RUN npm install
---> Using cache
---> 574c922e2ff5
Step 5/11 : ADD . .
---> 8d416dce229f
Step 6/11 : FROM node:carbon
---> ed145ef978c4
Step 7/11 : COPY --from=build /usr/src/app .
---> 0008a3a2fac8
Step 8/11 : ENV FORGE_CLIENT_ID=default
---> Running in 5efff0d539c2
Removing intermediate container 5efff0d539c2
---> 08ee432e37ed
Step 9/11 : ENV FORGE_CLIENT_SECRET=default
---> Running in 53e15aed2634
Removing intermediate container 53e15aed2634
---> 8dc4f8f03fab
Step 10/11 : EXPOSE 3000
---> Running in 8afb5e9034cb
Removing intermediate container 8afb5e9034cb
---> bcf445ff2897
Step 11/11 : CMD [ "npm", "start" ]
---> Running in fc5d20dc2a84
Removing intermediate container fc5d20dc2a84
---> 158b068617a5
Successfully built 158b068617a5
Successfully tagged autodesk-forge-docker:latest
Now, your Docker Image has been created. You can check your recently created image ID by typing
docker images
Running your image with -d
runs the container in detached mode, leaving the container running in the background. We will also pass in the values for our Forge Client ID & Secret ENV’s.
docker run -e FORGE_CLIENT_ID='YOURCLIENTID' -e FORGE_CLIENT_SECRET='YOURCLIENTSECRET' -d --name autodesk-forge-docker -p 3000:3000 autodesk-forge-docker
This will output your image Id. Congrats you have now dockerized your Forge Node.js application and it is running on port 3000.
You can also start your container by specifying a port mapping:
docker run -p 3001:3000 <image-name>.
Then is the port 3000 of your container mapped to the port 3001 of your local machine. So that you can access it through localhost:3001. See also the docker run reference for more details.
In order to get your container ID, you can obtain it with the following command.
docker ps
Followed by printing the logs of that container.
docker logs <container id>
Terminal output
> forgesample@1.0.0 start /
> node start.js
Starting at Wed Aug 15 2018 20:02:05 GMT+0000 (UTC)
Server listening on port 3000
Head over to http://localhost:3000/ to see your Autodesk Forge application running with Docker
Next time I will show you how to scale this to a Production environment using AWS ECR (Amazon Elastic Container Registry). Thanks for reading.