2

I have the following in my docker-compose.yml file:

volumes:
    - .:/var/www/app
    - my_modules:/var/www/app/node_modules

I do this because I don't have node_modules on my host and everything gets installed in the image and is located at /var/www/app/node_modules.

I have two questions regarding this:

  1. An empty folder gets created in my host named node_modules. If I add another volume (named or anonymous) to the list in my .yml file, it'll show up in my host directory in the same folder that contains my .yml file. From this answer, it seems to have to do with the fact that there's these two mappings going on simultaneously. However, why is the folder empty on my host? Shouldn't it either a) contain the files from the named volume or b) not show up at all on the host?

  2. How does Docker know to check the underlying /var/www/app/node_modules from the image when initializing the volume rather than just saying "Oh, node_modules doesn't exist" (since I'm assuming the host bind mount happens before the named volume gets initialized, hence /var/www/app should no longer have a folder named node_modules. It seems like it even works when I create a sample node_modules folder on my host and a new volume while keeping my_modules:/var/www/app/node_modulesβ€”it seems to still use the node_modules from the image rather than from the host (which is not what I expected, although not unwanted).

rb612
  • 5,280
  • 3
  • 30
  • 68

1 Answers1

8

As an implementation detail, Docker actually uses the Linux kernel filesystem mount facility whenever it mounts a volume. To mount a volume it has to be mounted on to a directory, so if the mount target doesn't already exist, it creates a new empty directory to be the mount point. If the mount point is itself inside a mounted volume, you'll see the empty directory get created, but the mount won't get echoed out.

(If you're on a Linux host, try running mount in a shell while the container is running.)

That is:

  • /container_root/app is a bind mount to /host_path/app; they are they same underlying files.
  • mkdir /container_root/app/node_modules creates /host_path/app/node_modules too.
  • Mounting something else on /container_root/app/node_modules doesn't cause anything to be mounted on /host_path/app/node_modules.
  • ...which leaves an empty /host_path/app/node_modules directory.

The first time you start a container, and only then, if you mount an empty volume into a container, the contents from the image get copied into the volume. You're telling Docker this directory contains critical data that needs to be persisted for longer than the lifespan of the container. It is not a magic "don't use the host directory volume" knob, and if you do things like change your package.json file, Docker will not update the contents of this volume.

David Maze
  • 130,717
  • 29
  • 175
  • 215
  • Thanks a lot! One thing that seems to not make sense is how if I run `docker-compose up -d` and then `docker-compose stop`, remove `node_modules` from the host, and then do `docker-compose up -d`, when I `ls` I see the empty `node_modules` folder again. I thought this wouldn't happen since the container isn't being recreated. Hence, if the container isn't being recreated and it's just being started again from a stopped state, I would think the folder wouldn't be created again in the host. – rb612 May 25 '19 at 05:32
  • I have created a followup question [here](https://stackoverflow.com/questions/56317302/does-stopping-docker-compose-containers-unmount-volumes). – rb612 May 26 '19 at 20:57