This is the third installment of my series, Can You Containerize It? Today, I will be teaching you how to use Docker to containerize an Express.js app! Express is a Node.js framework used to build API's. You can easily scale a containerized API to handle dynamic traffic. You can also take advantage of technologies that allow for zero-downtime deployment and are self-healing! Let's get started.
TLDR: Here is the fulling working code on my Github.
Install locally
Just like my previous posts, I would like to get Express running locally before I containerize it. This helps you debug your code if something goes wrong. You can refer to one of my two posts on Getting Started with Express.js in 5 minutes or How to Convert Express.js to Typescript based on whether you want to use JavaScript or TypeScript as your base. Both articles contain links to my Github. I am going to use TypeScript for this tutorial. The containerization process should essentially be the same for either one.
git clone https://github.com/fourgates/blog-express-ts-docker.git
cd blog-express-ts-docker/
git checkout part-2-typescript
npm i
npm run start
You should have express running locally!
server started at http://localhost:8080
Create Dockerfile
Next, let's create a Dockerfile in the root directory of the project (same folder where package.json
is). We will use this to create our "base" image.
FROM node:12
# Create app directory
WORKDIR /usr/src/app
# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY package*.json ./
# remove this line if you are not using TypeScript
COPY tsconfig.json ./
COPY tslint.json ./
RUN npm install
EXPOSE 8080
A couple of notes.
FROM node:12
- This is the base image we are using to build our own Express base image.WORKDIR /usr/src/app
- This sets a default directory for the image. Anytime you run a command for this image it will get run in this folder.COPY
- We want to copy dependency related files into our image. We needpackage.json
andpackage-lock.json
sonode
know what dependencies to install when runningnpm i
. Also, if you are using TypeScript you need to copy thetsconfig.json
to tellnode
how to compile your TypeScript andtslint.json
to be able to lint your project.
Create docker-compose.yml
Now that we have instructions for Docker to build a base image. Next, we need to create a docker-compose.yml
file to encapsulate commands for building a base image to develop our code in.
version: '3.7'
services:
express:
build:
context: .
dockerfile: Dockerfile
image: express/builder:0.0.1
container_name: express-container
ports:
- '8080:8080'
volumes:
- ./src:/usr/src/app/src
command: npm run start
A couple of notes.
version
- This is the version ofdocker-compose
to use. Newer versions add improved capabilities.services
- You can have docker start multiple containers for full-stack applications. A good use case for multiple services would be if you want to start up an Express server and a DynamoDb instance for your local API to interact with.build
- This is the build section of the compose. We are usingcontext
to point to where the Docker files are located. In this case, they are in the current directory.dockerfile
is used to point to the correct file with instructions on how to build the image.image
- This is the name Docker will give to your image once it is created.container_name
- This is the name that is used for the container when the images start.
Build Base Image
Let's build the base image!
docker-compose build
Start Express!
Finally, start your server!
docker-compose up dev
Success! :timetopartyemoji:
express-container | server started at http://localhost:8080
Conclusion
That's it! You can now develop code as you would any other Express app. You don't need to install any dependencies~ There are a few things we can do to improve the build time and image size but I will leave that exercise for a future post. You can also push this image to your favorite Docker repo and use it anywhere you would like. Happy Container, Happy Developer!
Here is the fulling working code on my Github.
Caveats
Remember to bump the image
version number and push a new base image any time dependencies change! This means anytime you update package.json there needs to be a new base image.
Pro Tip
docker ps
- This is a useful command to list all running containers.
docker ps -a
- List all containers, including those that are not running.