Search code examples
dockerdocker-composedocker-volumelarge-data-volumes

How to bind mount a local folder into several services in docker-compose, without having to repeat each time?


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!


Solution

  • 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! 😎