by Adam Brett

Docker Patterns - Transparent Development Volume

The Dev Volume or Dev Mount pattern is a cousin of the Cache Volume pattern. Instead of mounting a single directory to cache your dependencies, however, you mount your entire current working directory to allow you to run your code in a close approximation of your production environment.

Imagine the following relatively simple Dockerfile

FROM nodejs:6-alpine

ENV APPDIR=/usr/src/app

RUN mkdir -p $APPDIR
WORKDIR $APPDIR

COPY . $APPDIR

RUN npm install

CMD ['npm', 'start']

Nothing too surprising there, but it would be a pain if we had to re-build that image every time we wanted to run our code whilst we were developing.

You could develop on a normal NodeJS installation without touching docker - and that's a perfectly valid approach, but it can lead to a situation where your team are all developing on different versions and end up with "it works on my machine".

This is where the Dev Volume pattern can help. It looks like this:

docker run --rm -v ${PWD}:${PWD} -w ${PWD} -p 3000:3000 nodejs:6-alpine npm start

This simple command will mount your current working directory (your project) inside a NodeJS 6 image, and then run your npm start command. You could replace this with npm run start-dev or whatever if you have a separate dev entrypoint with live reload and so on.

This has three major benefits:

  1. your code runs on the same version of node that your image will be build on
  2. your team are all running the application on the same version of node, so there's no more "it works for me"
  3. You no-longer have to worry about getting new developers on your team "setup", you can checkout a project and as long as they have docker installed, can start developing almost instantly

There is a small drawback to this in that any files your project creates will be owned by root. This is a fairly standard problem for docker volume based patterns, and is usually overcome with the Run User pattern.

There is, of course, a docker-compose version of this pattern, and it looks like this:

app:
  image: node:6-alpine
  user: ${USER_ID}
  volumes:
    - ${PWD}:${PWD}
  working_dir: ${PWD}
  command: npm run start::dev
  ports:
    - 3000:3000

Which you can run with:

USER_ID=$(id -u) docker-compose up --force-recreate app

For exclusive content, including screen-casts, videos, and early beta access to my projects, subscribe to my email list below.


I love discussion, but not blog comments. If you want to comment on what's written above, head over to twitter.