dockerdocker-composedocker-swarm

One shared named volume with multiple paths


Is it possible to use one shared named volume with multiple paths ?

I want to avoid repetition (DRY pattern) and avoid the creation of many named volumes for different paths that must be centralized due to business requirements (backup policies and so on).

I created the following named volume vol-web based on NFS to share with many workers in my swarm cluster. But it can be reproduced locally. Just imagine that the volume points to a directory in your host.

docker volume create --driver local \
    --opt type=nfs \
    --opt o=addr=10.0.0.2,rw \
    --opt device=:/var/web \
    vol-web

The file below is only for test purposes, but I have many compose files, many services that will use this solution in the practice.

version: '3.8'

services:
  database:
    image: postgres:16.2
    container_name: mydb
    restart: always
    environment:
      - POSTGRES_USER=myuser
      - POSTGRES_PASSWORD=mypassword
    volumes:
      - vol-web/pgdata:/var/lib/postgresql/data
      - vol-web/config/pg/postgres-init.sh:/docker-entrypoint-initdb.d/postgres-init.sh
    ports:
      - "5432:5432"
  nginx:
    image: nginx:1.25.4
    container_name: my-nginx
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - vol-web/config/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - vol-web/certbot/conf:/etc/letsencrypt

volumes:
  vol-web:

I get actually the following error message:

service "database" refers to undefined volume vol-web/pgdata: invalid compose project

I am open for new solutions for this case.


Solution

  • Support for mounting volume subpaths is only available in Docker 26.0.0 (release March 20, 2024) and later (the pull request merged in janurary). This adds the subpath option to volume mounts.

    Using docker run, we can mount the pgdata subdirectory of the vol-web volume on /data like this:

    docker run -it --rm \
      --mount type=volume,source=vol-web,target=/data,volume-subpath=pgdata \
      alpine sh
    

    Support for this feature in docker compose was only merged a few days ago and is only available in the compose plugin version 2.26.0 and later; this doesn't appear to be available in a release of Docker at this time.

    Prior to the above versions it was not possible to mount a volume subpath.


    Unrelated to your question but important: when you create a volume like this:

    docker volume create --driver local \
        --opt type=nfs \
        --opt o=addr=10.0.0.2,rw \
        --opt device=:/var/web \
        vol-web
    

    And then use a volume entry like this in your compose file:

    volumes:
      vol-web:
    

    They are not referring to the same volume. Volume, network, and container names in your compose file get prefixed by your compose project name (typically the name of the directory that contains the compose file, but can also be set explicitly). If you want your compose file to reference an existing external volume, you would need to set it as external:

    volumes:
      vol-web:
        external: true