There are tens of thousands of blogs, articles and forum threads out there on containerizing a Node.js application. We have everything from outright bad advices to informed and tested opinions. This short post is about a very specific aspect of Dockerinzing a Node app, something that is usually not addressed or given as an after-thought in these articles.
Once you have a Node app up and running in Docker, things are well until you – like all good developers – start adding or removing NPM packages. Nasty things happen, such as:
- packages get installed on your local (host) filesystem but are not available inside the container
- packages get installed on your container’s filesystem but are not available on your local
- there’s a mismatch between versions of the same package in host and container
- permission issues while installing or removing packages
All these can be solved by correctly using Docker volumes. A volume is basically a way to make parts of container’s filesystem available to host and vice-versa. Not understanding volumes properly may also lead to one of the issues listed above.
I had a similar experience in one of my projects. See the fix:
As noted in the stackoverflow answer cited in the commit:
When docker builds the image, the node_modules directory is created within thehttps://stackoverflow.com/a/32785014/1775160
workerapp directory, and all the dependencies are installed there. Then on runtime the workerapp directory from outside docker is mounted into the docker instance (which does not have the installed node_modules), hiding the node_modules you just installed. You can verify this by removing the mounted volume from your docker-compose.yml.
This is a powerful thing to remember. Once you know how volumes work, you’ll be able to better troubleshoot your Node app when things are wrong. For example, when I recently installed a new NPM package in my local I knew I had to do something like this to make it available inside the container as well:
Why didn’t I just mount my host node_modules to container’s node_modules? Here’s the explanation:
An alternative approach is to mount host node_modules as a volume in container, but that will override container’s own node_modules folder with host’s. Keeping things independent allows for cleaner and easier troubleshooting of installed/missing packages.
This the approach I prefer, which of course is not certified gold. I works for me well. Besides, yarn installing packages each time container comes up does so incrementally (only new packages are fetched and installed). A win-win 🙂