dockerdocker-composedockerfile

Can we mount sub-directories of a named volume in docker?


The docker-compose file https://docs.docker.com/compose/compose-file/#/volumes-volume-driver shows various ways to mount host sub-directories relative to the compose file.

For example:

volumes:
   # Just specify a path and let the Engine create a volume
   - /var/lib/mysql
 
   # Specify an absolute path mapping
   - /opt/data:/var/lib/mysql
 
   # Path on the host, relative to the Compose file
   - ./cache:/tmp/cache
 
   # User-relative path
   - ~/configs:/etc/configs/:ro
 
   # Named volume
   - datavolume:/var/lib/mysql

Is is possible to mount a sub-directory of a named volume at a specific location? For example something like below, which I tried, but does not seem to work.

# Named volume
  - datavolume/sql_data:/var/lib/mysql

I am assuming I might be able to manage this by mounting the data volume to a location like /data and then in the Dockerfiles for each container, create symbolic links from the sub-directories to the locations.

for example in a docker-compose.yml file

volumes:
  - datavolume:/data

and then in the container Dockerfile

RUN ln -s /data/sql_data /var/lib/mysql

I started going down this path but it was getting messy and was not working. Before I either abandon that approach or invest the time debugging it, I wanted to make sure there was no way to just specify sub-directories of a named vollume.


Solution

  • 2023: As noted by Michael Bolli in the comments, that feature is now a work-in-progress:

    PR 45687: "volumes: Implement subpath mount"

    Make it possible to mount subdirectory of a named volume.

    Q1 2024: this is merged! Commit 31ccdbb.
    Possibly for Moby 26.0.

    [Documentation: docker/docs PR 20577 with example:

    Mount a volume subdirectory

    When you mount a volume to a container, you can specify a subdirectory of the volume to use, with the volume-subpath parameter for the --mount flag. The subdirectory that you specify must exist in the volume before you attempt to mount it into a container; if it doesn't exist, the mount fails.

    Specifying volume-subpath is useful if you only want to share a specific portion of a volume with a container. Say for example that you have multiple containers running and you want to store logs from each container in a shared volume. You can create a subdirectory for each container in the shared volume, and mount the subdirectory to the container.

    The following example creates a logs volume and initiates the subdirectories app1 and app2 in the volume. It then starts two containers and mounts one of the subdirectories of the logs volume to each container. This example assumes that the processes in the containers write their logs to /var/log/app1 and /var/log/app2.

    $ docker volume create logs
    $ docker run --rm \
      --mount src=logs,dst=/logs \
      alpine mkdir -p /logs/app1 /logs/app2
    $ docker run -d \
      --name=app1 \
      --mount src=logs,dst=/var/log/app1/,volume-subpath=app1 \
      app1:latest
    $ docker run -d \
      --name=app2 \
      --mount src=logs,dst=/var/log/app2,volume-subpath=app2 \
      app2:latest
    

    With this setup, the containers write their logs to separate subdirectories of the logs volume. The containers can't access the other container's logs.


    March 2024, as mentioned in issue 32582:

    CLI already supports it (starting from v26.0.0-rc1): docker/cli PR #4331

    (and you can already install it from the test channel)

    Compose support is still WIP (it needs to move to v26 first).

    March 2024: Paweł Gronowski confirms in the same issue:

    moby v26.0.0 is released, so you can already try out this feature.


    2016: No because compose/config/config.py#load(config_details) check if datavolume/sql_data matches a named volume (in compose/config/validation.py#match_named_volumes()).

    datavolume would, datavolume/sql_data would not.

    As memetech points out in the comments, the is an issue tracking this since April 2017:
    moby/moby issue 32582: "[feature] Allow mounting sub-directories of named volumes".

    In that issue, Joohansson adds (see comment)

    In the meantime, I use this workaround to mount the whole volume on a separate path and then symlink it to the sub path.

    # In the Dockerfile:
    RUN mkdir -p /data/subdir
    RUN ln -s /data/subdir /var/www/subdir
    

    Then mount the volume as normal.
    The /subdir must exist in the volume.

    docker run -d -v myvol:/data mycontainer
    

    Now anything read or written by the webserver will be stored in the volume subdir and can't access the other data.