This blog aims to demonstrate how to instal a Node.js application within a Docker container. This blog is not meant to be deployed in production; instead, it is meant for development. This manual also assumes you know the basics of how a Node.js application is put together, and you have a functioning Docker installation.
A container is a "box or bucket" that Docker gives you the ability to pack an application into together with its environment and all of its dependencies. Usually, a container consists of an application running in a particular environment of a Linux operating system. A container is a running instance of an image, while an image is the blueprint for a container.
Create a blank file with the name Dockerfile:
$touch Dockerfile
Open the Dockerfile in your favorite text editor {I use nano editor}
The first thing we need to do is define from which image we want to build. The most recent LTS (long-term support) version 16 of a node is used in this article and is accessible from the Docker Hub:
FROM node:16
Next, we create a directory to copy the application code inside the image, this will be the working directory for our application:
# Create an app directory
WORKDIR /usr/src/app
This image comes with Node.js and NPM already installed in it so the next thing we need to do is to install our app dependencies using the npm binary so that there is all dependencies are installed. Please be aware that a package-lock.json file won't be generated if you are using npm version 4 or earlier.
# Install app dependencies
# A wildcard is used to make sure both package.json AND package-lock.json are copied.
# where available (npm@5+)
COPY package*.json ./
RUN npm install
# If we are building our code for production
# RUN npm ci --only=production
Note that, we are only copying the package.json file and not the working directory as a whole. This enables us to utilize cached Docker layers. Furthermore, the npm ci command, specified in the comments, helps provide faster, more reliable, reproducible builds for production environments. You can read more details about this here.
Use the COPY command to transfer the source code for our app inside the Docker image:
# Bundle app source
COPY...
Our app now binds to port 8080 so we have used the EXPOSE instruction to have it mapped by the docker daemon:
EXPOSE 8080
Last but not least, we will use CMD, which defines our runtime, to define the command that runs our application. Here, we'll launch our server using node server.js:
CMD [ "node", "server.js" ]
Our Dockerfile should now look like this once we collect all commands:
FROM node:16
# Create an app directory
WORKDIR /usr/src/app
# Install app dependencies
# A wildcard is used to make sure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY package*.json ./
RUN npm install
# If we are building your code for production
# RUN npm ci --only=production
# Bundle app source
COPY.
EXPOSE 8080
CMD [ "node", "server.js" ]
Create a .dockerignore file in the same directory as our Dockerfile is situated with the following content in it:
node_modules
npm-debug.log
This will prevent our local node modules and npm debug logs from being copied onto our Docker image and prevent overwriting the modules installed within your image.
Go to the directory in which our Dockerfile is located and run the following command to build the Docker image. The -t flag lets us tag our image so it's easier to get the image later using the docker images command:
docker build. -t <your username>/node-web-app
Our image will now be listed by Docker using :
$ docker images
# Example
REPOSITORY TAG ID CREATED
node 16 3b66eb585643 5 days ago
<your username>/node-web-app latest d64d3505b0d2 1 minute ago
Running our image with -d will run the container in a detached mode which leaves our container running in the background. A public port is redirected and mapped to a private port inside the container using the -p flag. Run the image which we have previously built:
docker run -p 3000:8080 -d <your username>/node-web-app
Print the output of our app:
# To get all running containers with container ID
$ docker ps
# Print logs of a container
$ docker logs <container id>
# Example
Running on http://localhost:8080
If we need to go inside the container we have to use the exec command:
# Enter into container using:
$ docker exec -it <container id> /bin/bash
To test the app, get the port of our app that Docker is mapped with:
$ docker ps
# Example
ID IMAGE COMMAND ... PORTS
ecce33b30ebf <your username>/node-web-app:latest npm start ... 49160->8080
In the example above, The 8080 port inside the container was mapped by Docker to port 49160 on your computer.
You can now use curl to call your application ( if necessary, install curl using sudo apt-get install curl):
$ curl -i localhost:3000
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/HTML; charset=utf-8
Content-Length: 12
ETag: W/"c-M6tWOb/Y57lesdjQuHeB1P/qTV0"
Date: Mon, 13 Nov 2017 20:53:59 GMT
Connection: keep-alive
Hello world 3 baar
To close the app we started, In docker, we run the kill command. The kill command uses the container's ID.
# Stop the running container
$ docker kill <container id>
<container id>
Now check that the app has stopped or running
$ curl -i localhost:3000
Curl: (7) Connection to localhost port 3000 was unsuccessful: Connection refused.
I hope this blog helped you regarding how to deploy and run a simple Node.js application on Docker.