4

i am confused if there is a link between docker build context and volumes, i have the following docker-compose and could use some clarifications.
The context is set at ./app and then the volumes are referencing the same ./app, where is that volume created since its not referenced in the volumes section below (only contains db_data, unused), and what does type of volume mean. Thanks in advance

web-client:
 image: some-image
 build:
   context: ./app
   dockerfile: Dockerfile
 ports:
   - "8081:3000"
 volumes:
     - ./app:/opt/app:delegated
     - ./app/package-lock.json:/opt/package-lock.json
     - notused:/opt/app/node_modules
volumes:
  db_data:
  notused:
ashk
  • 41
  • 1
  • 4

1 Answers1

1

You should delete that volumes: block entirely. It's unnecessary and can lead to inconsistent results.

volumes:
     - ./app:/opt/app:delegated

This creates a bind mount: the /opt/app directory in the container is the ./app directory on the host. Anything that the Dockerfile does in that directory (likely its entire installation process) is hidden.

The bind mount isn't a Docker object and it won't show up in places like docker volume ls.

volumes:
     - notused:/opt/app/node_modules

This replaces the contents of your node_modules directory with the contents of a Docker named volume. The contents of that named volume will take precedence over both what's in the image and what's in the bind-mounted parent directory. As far as Docker knows, this directory contains opaque user data and will never update it. That is, this setup causes Docker to ignore changes in your package.json file, even if you re-run docker-compose build.

This setup takes advantage of a special case in Docker named volumes: the very first time an empty named volume is mounted into a container, Docker copies the contents of the image into the volume. This only happens the very first time you run the container (it is not a generic pass-through into the image) and only on Docker named volumes (not bind mounts or volumes in other runtimes like Kubernetes).

Many setups use an anonymous volume here, just listing /opt/app/node_modules with no colon at all under volumes:. This behaves identically to a named volume, except it doesn't have a name.

volumes:
    - ./app/package-lock.json:/opt/package-lock.json

This is a bind mount, just like the first case, but it mounts a file into a different directory. This is one place where the "inconsistent results" I mentioned up front can come in: if you want to use the built Docker image without separately distributing the application source, rearranging files with bind mounts means that the filesystem layout is different with and without the volumes.

The related trouble I more often see with a setup like this is doing some installation steps or moving files in a Dockerfile. Since the bind mounts hide everything in the container, any of this work will be lost. Imagine you RUN yarn build; the image would contain an /opt/app/dist directory but the bind mount hides that.

Usually the motivation for this setup is to work directly on host code without rebuilding the image. However, the volume mounts hide everything in the image build, so you may as well run an unmodified node image; and if you're running code bind-mounted into an unmodified node image, you may as well just run Node without Docker involved at all. A useful development setup can be to run databases and other dependencies in Docker but to use a normal non-container language runtime for day-to-day development.

David Maze
  • 130,717
  • 29
  • 175
  • 215
  • thanks for taking the time to write a very detailed response. Can you talk more about which volumes: block to delete ? The following is required for any named volume `volumes: db_data: notused:` – ashk Mar 09 '22 at 20:19
  • If you're mounting that `db_data:` volume as the backing data store for a database container (`{ image: postgres, volumes: [db_data:/var/lib/postgresql/data] }`) that makes sense. But the `volumes:` in the `web-client` container that overwrite the image's code should be removed, and you don't need the top-level declaration for the `notused` volume either. – David Maze Mar 10 '22 at 02:28