0

I have a docker-compose.yml file where I'm defining several services, each resulting in an individual container. In short it looks like this:

version: "3.9"
services:
    dev_1:
        build:
            context: .
            dockerfile: ./Dockerfile
            target: dev_1

        volumes:
            -   type: bind
                source: /home/foo
                target: /home/bar

    dev_2:
        build:
            context: .
            dockerfile: ./Dockerfile
            target: dev_2

        volumes:
            -   type: bind
                source: /home/foo
                target: /home/bar

You can see that for each service I have to bind mount the volume again, by copying the same lines of code. But in my application I have several such folders which I want to mount into all the services, but without having to copy all the lines again and again.

Is there a way to shorten this, e.g. by using the volumes directive?

So far I only found suggestions to use a shared volume, but this is not practical for me, as such a volume copies the data into the volume. But I have plenty of data (Terrabytes) which I don't want to copy. I just want to bind mount it.

The docker compose version doesn't matter - right now I'm using 3.9. As long as it works everything is allowed.

Thanks in advance!

burn4science
  • 61
  • 2
  • 4
  • What's in these files? If they're read-only, can you build them into the image(s) without a bind mount? If multiple containers are writing to them, how do you manage concurrent writes? (Can you get rid of these volume mounts entirely?) – David Maze Feb 24 '23 at 01:31
  • Those folders are my data sources (lots of images, measurement files, ...) and also my result depots (e.g. I manipulate images and need to save them again, which needs space). Some sources are mounted network drives, others are folders from my raid0 disk. Race conditions during file access shouldn't happen as I'm just running one of the containers at a time. – burn4science Feb 24 '23 at 08:31

1 Answers1

1

I found an answer on medium, that solves my problem: using anchors, aliases and the x-flag makes it possible to define the volumes in a central service, which can then be reused in the other services:

version: "3.9"

x-volumes_all: &volumes_all
    volumes:
        - &vol1 /home/foo1:/home/bar1
        - &vol2 /home/foo2:/home/bar2

services:
    <<: *volumes_all
    dev_1:
        build:
            context: .
            dockerfile: ./Dockerfile
            target: dev_1

        volumes:
            -   *vol1

    dev_2:
        build:
            context: .
            dockerfile: ./Dockerfile
            target: dev_2

        volumes:
            -   *vol2

At first, I define x-volumes_all as the common service - the preceding x- indicates that the service is hidden and only there to be reused in other services. Additionally, I use the anchor & to give it an arbitrary name (&volumes_all). In the volumes section I simply define my bind mounts, again using anchors to give each volume a name (&vol1 and &vol2).

Later, in my service section I import the hidden service (<<: *volumes_all) by dereferencing the alias using *. In the same way I can now include the individual volumes, called again by * and their respective name.

That way I reduce errors as I only need to define everything once.

Found here: Don’t Repeat Yourself with Anchors, Aliases and Extensions in Docker Compose Files

Thanks folks!

burn4science
  • 61
  • 2
  • 4
  • The syntax is cool, but I don't think you need it in this case. Docker compose lets you define volumes as a [top-level element](https://docs.docker.com/compose/compose-file/#volumes-top-level-element) and then they are available to all other services. – WiringHarness Mar 19 '23 at 07:58
  • 1
    See also [this useful answer](https://stackoverflow.com/a/55952189) – WiringHarness Mar 19 '23 at 08:04
  • Nice, thanks! I was looking for something like this, but did never find the right combination of driver and driver-opts, nothing worked. But your linked solution works, thanks. However, I must admit that I think that it's still not perfect. The `volumes` statement is not very intuitive to read. Also I can only define the source there, not the target. Or can I? So I'd always have to define the target in each individual service... – burn4science Mar 20 '23 at 09:18