Containerising a Node Express App
If you need an example application to use try this Simple JSON API
In this basic example of how to containerize a node express app we will use Docker. It is assumed that that you have a working express application that you are ready to put into a container for deployment purposes.
Also assumed is that you have access to the Docker CLI which you can verify by running the following command in your terminal:
docker -v
# Docker version 19.03.5, build 633a0ea (your version may differ)
Building A Container
Navigate to your project folder and create a Dockerfile
Note: This file is case sensitive so use a capital 'D'
# Use apline linux where ever possible
# to keep container sizes to a minumum
FROM node:alpine
# Application Code
WORKDIR /app
# Install app dependencies
COPY package*.json ./
# Install Dependancies
RUN npm install
# Expose port 3030 from the container
EXPOSE 3030
# Run server by default
CMD ["npm", "start"]
# Add application code
COPY . .
Each command in the Dockerfile results in a layer
that is added to the base image layers. It is worth thinking about the order of operation here. Most updates that you make to your app after having deployed a build for testing will be code changes. As you can by the order of the commands copying in the application code is the last step. So if the only change is something in your application code only the last layer would need to be re-build in subsequent builds. If you were to add a new package to your project, then all the layers down to COPY package*.json ./
would need to be discarded and rebuilt.
The most important part of this file is the EXPOSE
port number, in my example app it listens on port 3000, yours may be different, change the port number to suit if required.
If you are using the Simple JSON API example, this is all tha should be required to build your container. Using the docker CLI we can initiate a build using the docker build
command:
docker build -t example-json-api:dev .
In this command the -t
stands for the tag name and the .
is just referring to the current directory as the location of the Dockerfile
Once the build is completed you should see the last entry on the terminal indicating success:
# Successfully tagged example-json-api:dev
Now you should be able to see this new image in your list of local images:
docker images
# REPOSITORY TAG IMAGE ID CREATED SIZE
# example-json-api dev 6ba575ffb51f 2 minutes ago 83.2MB
Running A Container
You can test run the image with the following command:
docker run --rm -p 3000:3000 example-json-api:dev
The --rm
flag here will automatically remove the container from the local container instances once you <ctrl> + C
to stop the running container.
The -p
flag tells docker to map local ports to the exposed container ports <local port>:<container port>
Then you should be able to interact your app on the port that is exposed. In this example by opening a new termainal and using curl. The running container should log to the console when new requests are recieved.
# [2020-04-25T16:01:51.034Z] Example JSON API listening at http://localhost:3000
# [2020-04-25T16:01:54.271Z] POST /echo -> {"message":"This is my new JSON API"}
# [2020-04-25T16:01:55.284Z] GET /
Stop the container by using <ctrl> + C
in the running container terminal.
Saving A Container
Docker CLI has a very useful save command that we can use to convert the container into a .tar.gz
file which can then be shared.
docker save example-json-api:dev | gzip > example-json-api.tar.gz
Alternitively if you prefer not to gzip the result you will end up with a .tar
file
docker save example-json-api:dev > example-json-api.tar
Delete A Container
Using Docker CLI you can remove a container image as long as it's not currently running on in a container instance with the following command:
docker rmi example-json-api:dev
You can check that it's successfully removed from your local images by running this command and verifying that it's not in the list:
docker images
Loading A Container
Docker CLI also has a load command for extracting .tar
or .tar.gz
archives that you may have saved.
docker load --input example-json-api.tar.gz
Or if you have a .tar
file
docker load --input example-json-api.tar
You can check that it's successfully loaded into your local images by running this command and verifying that it is in the list:
docker images
# REPOSITORY TAG IMAGE ID CREATED SIZE
# example-json-api dev 6ba575ffb51f 5 minutes ago 83.2MB
The beauty of containerising your application is that it will be able to run on any platform that docker can run on, and there will not be any cross platform issues that mean there are subtle differences in how your app runs or unexpected bugs based on different underlying hardware.