5

I want to use Docker to create development environments for a simple node.js project. I'd like to install my project's dependencies (they are all npm packages) inside the docker container (so they won't touch my host) and still mount my code using a volume. So, the container should be able to find the node_modules folder at the path where I mount the volume, but I should not see it from the host.

This is my Dockerfile:

FROM node:6


RUN mkdir /code
COPY package.json /code/package.json
WORKDIR /code

RUN npm install

This is how I run it:

docker build --tag my-dev-env .

docker run --rm --interactive --tty --volume $(pwd):/code my-dev-env npm test

And this is my package.json:

  {
    "private": true,
    "name": "my-project",
    "version": "0.0.0",
    "description": "My project",
    "scripts": {
      "test": "jasmine"
    },
    "devDependencies": {
      "jasmine": "2.4"
    },
    "license": "MIT"
  }

It fails because it can't find jasmine, so it's not really installing it:

> jasmine

sh: 1: jasmine: not found

Can what I want be accomplished with Docker? An alternative would be to install the packages globally. I also tried npm install -g to no avail.

I'm on Debian with Docker version 1.12.1, build 23cf638.

Randy Eels
  • 101
  • 1
  • 5

2 Answers2

5

The solution is to also declare /code/node_modules as a volume, only without bind-mounting it to any directory in the host. Like this:

docker run --rm --interactive --tty --volume /code/node_modules --volume $(pwd):/code my-dev-env npm test

As indicated by @JesusRT, npm install was working just fine but bind-mounting $(pwd) to /code alone was shadowing the existing contents of /code in the image. We can recover whatever we want from /code in the container by declaring it as a data volume -- in this case, just /code/node_modules, as shown above.

A very similar problem is already discussed in Docker-compose: node_modules not present in a volume after npm install succeeds.

Randy Eels
  • 101
  • 1
  • 5
  • its also helpful to put your docker run command into a yaml file then launch it using docker-compose ... especially when you have many volumes and certainly once you involve multiple containers – Scott Stensland Dec 29 '17 at 18:53
2

The issue here is that you are overwriting the /code folder.

Note that you are executing the npm install command at building time, so the image that is created has in the /code folder the node_modules folder. The problem is that you are mounting a volume in the /code folder when executing the docker run command, so this folder will be overwritten with the content of your local machine.

One approach could be executing the npm install before the npm test command:

docker run --rm --interactive --tty my-dev-env npm install && npm test

Also, in order to the execution of the command jasmine works properly, you will have to modify your package.json as follow below:

"scripts": {
      "test": "./node_modules/.bin/jasmine"
    }
JesusTinoco
  • 9,130
  • 3
  • 26
  • 22
  • 1
    Fix this by moving your src down one level and mounting that (-v `pwd`/src:/code/src) or turning the necessary folders to keep into extra volumes which will be initialized with the data from the image (-v /code/node_modules) – Paul Becotte Aug 22 '16 at 20:43
  • @JesusRT The approach you mention is not really what I want, as I described. And the `package.json` modification is not necessary, since npm sources ./node_modules/.bin in the shell which runs npm test, just before running the given command. But your diagnosis is all right and I have found the answer, so I'm posting it. Sorry that I can't upvote you yet :/, and thanks! – Randy Eels Aug 23 '16 at 20:23