Docker has made our lives as developers easier. With just a few commands, we can start all kinds of programs and services without having to deal with the tedious installation of dependencies. Countless Docker images are freely available on Docker Hub. Whether you want to start your own open-source continuous integration & deployment server, such as Strider, or your own NPM registry with https://verdaccio.org/, the possibilities are endless.
But these are mostly ready-made Docker images I was talking about. But for your own projects, you have to build your own Docker image. And in this article, I will show and describe in a few words how you can put your next NodeJS application into a Docker image. Here we go.
A simple Dockerfile
looks something like this:
# We use the latest nodejs@14 image as our base image
FROM node:14-alpine
# set the default NODE_NEV to production
ENV NODE ENV=production
# make sure everything happens inside the /app folder
WORKDIR/app
# now we cache the node_modules layer
COPY ["package.json", "package-lock.json", "./"]
# install your dependencies
RUN npm install
# copy the source
COPY /src .
# and start the app
CMD ["node", "server. js"]
But what if you need to build the app first before you can run it? Let's take a look at this by using a multi-stage build.
# We make use of ARG to set some variables that we
# can use in the Dockerfile
ARG node_version=14
ARG node_image=node:${node_version}-alpine
# STAGE 1: This is the "builder" stage where we build the
# application and give this step a name: "builder"
FROM $node_image as builder
ENV NODE ENV=production
WORKDIR/app
COPY ["package.json", "package-lock.json", "./"]
# compared to the first example we now install
# _all_ dependencies including devDependencies
RUN npm install
# copy the source
COPY /src .
# now build the app
RUN npm build
# STAGE 2: in this stage, we reduce the size of the
# image by only installing production dependencies
FROM $node_image as production
WORKDIR /app/
# install _only production_ dependencies to keep the
# docker image small
COPY --from=builder /app/package.json /app/package-lock.json ./
RUN npm install --production
# copy the build from the first stage (e.g. the dist folder)
COPY --from=builder /app/dist ./dist
# and start the bundled app
CMD ["node", "dist/index. js"]
This is it. You now have the option to choose between a multi-stage or a single-stage Dockerfile for your next project. Of course, we could optimize some things still and apply different approaches, but that's maybe part of another story of my #90DaysOfProse challenge.
Cu,
Stefan
PS: Thanks Oliver for the inspiration for this article.