Efficient Docker with the new Yarn package manager & native packages like Bcrypt for Node.js apps

Jinesh Shah
Arthur Design & Engineering
3 min readJan 20, 2017

--

I recently switched all applications for my company to Yarn because it is just so fast. However, integrating with Docker is a little more complicated. Here, I’ll walk through the Dockerfile (and two other files that you need) to build an efficient and fast Docker deployment.

The three files you need

I’ve seen a lot of Node.js Dockerfile examples, but what a lot of them miss is that if you want to build a Docker image that includes modules with native components, you need three files:

1) build.sh

The final file is your build bash script. This file is important so that you only have to type one command (i.e. ./build.sh) to build your container and upload it.

2) Dockerfile

You need the actual Dockerfile which will manage building your application.

3) .Dockerignore

If you have any native modules, such as the popular bcrypt, you’ll need a .Dockerignore file as well.

So let’s get started…

The build script

Here is the structure of my build script:

#!/bin/bash# install node_modules and deploy application to production
yarn
npm run deploy
# build your docker image
docker build...
# push your docker image
docker push...
# run cleanup commands so you don't amass images that you don't need
docker rm -v $(docker ps -a -q -f status=exited) 2>&1
docker rmi $(docker images -f "dangling=true" -q) 2>&1

What’s important is the order of things. Unlike some other Docker setups that I’ve seen, I prefer to deploy the application to production from my bash script rather than the Dockerfile. The big reason for this is that I don’t need to install global build modules in my Dockerfile. I simply deploy from my computer and add the final files to my Docker image. The other important piece is to run the cleanup at the end. Otherwise, you’ll have gigs of Docker images taking up space on your computer.

The Dockerfile

Here is the structure of my Dockerfile:

# Set the base image
FROM node:X.X.X
# File Author / Maintainer
MAINTAINER XXXXXXXXX
# Define working directory
WORKDIR /var/www/api
# Install yarn
RUN apt-get update && apt-get install -y apt-transport-https
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update && apt-get install yarn
# Install node_modules with yarn
ADD package.json yarn.lock /tmp/
RUN cd /tmp && yarn
RUN mkdir -p /var/www/api && cd /var/www/api && ln -s /tmp/node_modules
# Copy app
COPY . /var/www/api
# Expose port
EXPOSE 8000
# Run app
CMD ["npm","start"]

What’s important here is that you install yarn then do other things because it will cache on subsequent builds. In addition, by placing your package.json & yarn.lock files in a /tmp/ folder, you can install your node_modules in a /tmp/ folder, then copy them to the main folder which also caches node_modules. Finally, you can copy your application into the Docker image (assuming you’ve already deployed it).

The .Dockerignore

Here is the structure of my .Dockerignore:

node_modules

That’s right, this file only has one line. The reason you need this line is because when you install your node_modules on your personal machine, modules like bcrypt cannot simply be copied over. Bcrypt must be installed in the environment it will be used because it must be compiled for that environemnt. By ignoring the node_modules folder, don’t copy it over, but rather use the folder you generate in the Dockerfile.

Final Thoughts

I don’t consider myself an expert, but based on my research, this is the best Docker setup for my needs. However, I’m always open to learning more, and if you have suggestions to improve this setup, please let me know!

About Me

I am a Co-Founder at a company called Arthur, a membership for women to discover the best emerging designers. We are built with Universal React.js, Redux, Node.js, Koa, Docker & PostgreSQL.

Interested in learning more? Get in Touch!

--

--