Search code examples
node.jsdockerdocker-composedockerfilenode-modules

Keeping node_modules up to date in docker


I'm working with a team on a repo built in Docker and Node. When someone else installs node packages, I git pull those changes to package.json and package-lock.json.

I can't just run docker-compose build and then docker-compose up, though, to install these new node packages. I have to first docker-compose down -v. This is because we're using a volume to store the node modules. We're not tied to this, and frankly would rather just store the modules in a docker image layer. But then, when we bind the app volume (- .:/app in docker-compose.yml), the node_modules folder in the image is shadowed.

It feels like we're taking the wrong approach to this, but this seems to be what the generally accepted practice is. Our setup is based on "Lessons from Building a Node App in Docker"

Our Dockerfile:

FROM node:8.4.0
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install --loglevel=error --progess=false
COPY . /app/

Our docker-compose.yml:

---
version: '2.1'

services:
  main:
    build:
      context: .
    volumes:
      - .:/app
      - /app/node_modules
    container_name: main
    command: ['node', 'index.js']

My understanding of the issue is that, in the docker-compose.yml file, The volume - /app/node_modules creates a volume that copies the node modules from inside the image layer into a volume, meaning that when we build the app again with a different package.json, the image is updated but not the volume. downing the volume forces it to re-copy from the updated image node_modules, which is why that works. Please let me know if my understanding is incorrect :)

We're running in AWS ECS, so unfortunately we can only use docker features available in 17.03.2-ce (no multi-stage docker files for now).


Solution

  • This is an old question but in case anyone else comes here with the same issue, I struggled with this too and this is how I could achieve the desired behaviour:

    docker-compose up --build --renew-anon-volumes
    

    According to the documentation on docker-compose up https://docs.docker.com/engine/reference/commandline/compose_up/

    Option Short Description
    --renew-anon-volumes -V Recreate anonymous volumes instead of retrieving data from the previous containers.

    With this, you not only build a new image, but also override the original volume used to store node_modules. Note that it doesn't work with named volumes. If you use named volumes, you'd need to manually remove that volume with docker volume rm <volume-name> before running docker-compose up again.

    The understanding of how volumes work from the original question seems sound. Readers may also find the following discussion in the Github issue beneficial to understanding it.

    https://github.com/moby/moby/issues/30647#issuecomment-276882545