My Dockerfile takes care of setting up a simple CLI node app. If I add a ‘CMD npm link’ instruction at the end, I expect it to create a symlink that I can then use to invoke my .js entrypoint.
When I build the image, it all appears to go well, including running the aforementioned CMD. Yet, when I create a container from the built image by running it, I can’t invoke the CLI/program using the symlink. I have to manually run npm link in the shell to get it to work, even through npm link should have run as part of the image creation (?).
I can’t say I fully understand osxfs - and I also don’t use npm-link for cli apps unless I’m testing them. This what I could find in the documentation
Mounting/unmounting OS X volumes that are also bind mounted into containers may result in unexpected behavior in those containers. Unmount events are not supported. Mount export support is planned but is still under development.
Symlinks
Symlinks are shared unmodified. This may cause issues when symlinks contain paths that rely on the default case-insensitivity of the default OS X file system, HFS+.
File types
Symlinks, hardlinks, socket files, named pipes, regular files, and directories are supported. Socket files and named pipes only transmit between containers and between OS X processes – no transmission across the hypervisor is supported,
Honestly I’ve never thought about running CMD npm link in a Dockerfile, but there’s other ways to accomplish the same goal. For example, I use the glances (system monitor) with docker, so I just wrote an alias glances=docker run ... in my dot files. I’ve also worked with and contributed to a a few cli apps using node/npm, so I’m familiar with 3 or 4 different ways to do it. I can build a node app to run docker via the cli, but I’ve never attempted using a docker container for the base of an npm cli app
CMD sets the command to run if you docker run the image. CMD is not run and its effects are not available in the built image. CMD only supplies the default command to use when no other command is specified on the command line.
For example, if you build this Dockerfile:
FROM alpine
CMD touch TEST_FILE
with docker build -t test-image . and then run it with docker run --rm -it test-image ls, you will observe:
bin etc lib media proc run sys usr
dev home linuxrc mnt root sbin tmp var
Thank you! This is useful. I have not found a way to address this in a practical way just yet, but it certainly made me think about the implications (and feasibility) of using symlinks in a container.
Thank you very much David. This did indeed solve it for me. I obviously did not have a solid understanding of the differences between CMD and RUN. I think doing a npm link may not be a sensible thing to do, but for the time being, replacing a CMD with a RUN at least does what I need it do. Again, thank you!
Interesting… thanks for the clarifying RUN vs CMD - if npm link works - that might be a really simple way to link cli apps globally… I’ve been working with this library recently https://github.com/matthieudelaro/nut attempted to make a brew for it so it was easier to install. But I couldn’t figure out how to mix docker / brew, and the binary itself needed signed permissions - so I just used node to link it in the path npm install -g nut-bin - and it worked, but using npm link is intriguing because the nut is built with docker. Thanks for raising this issue.
Has anyone been able to figure out how to use npm link with Docker? In my case I would like to run a server in a docker container than is npm-linked to a local module. This generates a symlink like this:
At GoSquared they use volumes for each symlinked module in docker-compose. But this will be problematic for nested npm links and it is complicated.
I think the only solution is to mount your npm linked root folders (e.g. ~/dev) and hook the Node require resolver and redirect requests for modules to the mounted dir path.
I’ve implemented the redirection already because I wanted to dedupe npm linked modules for performance reasons which is a problem with npm2 and npm3. I am happy because it was a lot of work, and now I find this perfect use case for it.