About Archives
 

Using Nodemon+Forever in Docker

 

“Static” Dockerfile

When I’ve started with Docker, I thought that the only way one could
input files to a Docker container was through the ADD/COPY commands in
the Dockerfile:

1
2
3
4
5
6
FROM node:5.0.0
RUN npm install -g forever
ADD app /usr/src/myapp
WORKDIR /usr/src/myapp
RUN npm install
CMD npm start

Every time I wanted to test a change inside of Docker, I would run my build.sh:

1
2
docker build -t francolaiuppa/project .
docker run -it --rm francolaiuppa/project

Instead of staring at a build screen, I could make a coffee,
then test my change (“please don’t break!”), edit, repeat.

Eventually this led me to test/develop locally (without Docker) using nodemon
in order to save time, and building the Docker image before releasing
to the development server, only to find out that there was a Docker gotcha
that I couldn’t see because I was running outside of the container… painful.

How to make it better? (i.e “Dynamic” Dockerfile)

There’s a Dockerfile command called VOLUME which allows us to define
a folder/file that will get mounted to the container.
Anyone running this image can then use the –volume flag, and mount
the project code directory:

1
2
3
4
5
FROM node:5.0.0
RUN npm install -g forever
VOLUME /usr/src/myapp
WORKDIR /usr/src/myapp
CMD npm start

Then we build (only once!) + run:

1
docker run -it --rm --volume $(pwd)/app:/usr/src/myapp francolaiuppa/project

Sure, now the files get updated automatically inside of the container, but
that does not trigger a reset as forever cannot watch files (at least
not efficiently in my previous attempts), so I had to write rs and press Enter.
Definitely better but not there yet.

What if we run nodemon supervised by forever? I’ve tried it

1
docker run -it --rm --volume $(pwd)/app:/usr/src/myapp francolaiuppa/project forever -c 'nodemon ' index.js

But you can’t never exit the process (at least not by Ctrl+c). Only by docker kill. Not elegant.

The key is in RTFM, as always. The nodemon documentation has a clear example on how to do it

1
docker run -it --rm --volume $(pwd)/app:/usr/src/myapp francolaiuppa/project forever -c 'nodemon --exitcrash ' index.js

Yes! That was it! Now I can develop my apps without having to wait a millon years!
Every edit I make gets reloaded automatically, and if the process fails and exits, forever will
respawn it.

Notes about file/folder permissions

Every time you run npm install from inside of the docker container, the files will get
written as “root” on your host machine. This is not desirable as your text editor will complain.
To fix this, you can chown from inside the container to recover your permissions:

1
docker run -it --rm --volume $(pwd)/app:/usr/src/myapp -e UID=$(id -u) francolaiuppa/project chown -R $UID .

Notes about npm install

After you’ve dealt with the permissions gotcha, another problem you’ll end up experiencing sooner
or later is the fact that executing npm install outside of the container will build the packages
in a way, but doing it inside of the container will have different results.
This may take you to weird bugs or messages saying that you need to run npm rebuild module-name-here,
normally because your local node version is different than the one the Docker image uses.

Because of this, it is recommended that you run all the npm install build tasks
from inside the container and just leave your code-editing tasks outside of Docker.