140
votes

I'm using docker-compose and v3. I'm trying to mount a volume in docker:

./appdata:/appdata

I'd like to have this as a volume and then reference that volume from multiple containers. The volume configuration reference only shows data-volume: as a named volume, with no value, so it doesn't look like the above.

services:

    nginx:
        build: ./nginx/
        ports:
            - 80:80
        links:
            - php
        volumes:
            - app-volume

    php:
        build: ./php/
        expose:
            - 9000
        volumes:
            - app-volume

volumes:
     app-volume: ./appdata:/appdata

This gives me:

ERROR: In file './docker-compose.yml', volume 'app-volume' must be a mapping not a string.

Obviously I know I need to change the volumes key/value pair, but I'm not sure how to change this so I can share a volume between services.

I've also checked out volumes_from but this effectively just allows inheritance from other containers. I've seen someone use volumes_from on another container that contains the mapping they want, but with command: true set so that the container is never actually run, which to me just seems like a hack.

How can I do this?


Note, I do have the following working:

nginx:
    volumes:
        - ./appdata:/appdata
php:
    volumes:
        - ./appdata:/appdata

But that's just duplication and is something I'm hoping a named volume could help me avoid :-)

4
You can find the answer in this answer: stackoverflow.com/a/49920624Isen Ng

4 Answers

178
votes

The named volumes can be shared across containers in the following way:

services:
    nginx:
        build: ./nginx/
        ports:
            - 80:80
        links:
            - php
        volumes:
            - app-volume:location_in_the_container

    php:
        build: ./php/
        expose:
            - 9000
        volumes:
            - app-volume:location_in_the_container

volumes:
     app-volume: 

Here's an example config that I use for better understanding. I'm exposing the static files generated from my web container to a named volume called static-content which is then read and served by the nginx container:

services:
  nginx:
    container_name: nginx
    build: ./nginx/

    volumes:
      - static-content:/usr/src/app

  web:
    container_name: web
    env_file: .env
    volumes:
      - static-content:/usr/src/app/public
    environment:
      - NODE_ENV=production

    command: npm run package

volumes:
  static-content:
41
votes

This solves it without using named volumes:

      volumes:
          - ./appdata:/appdata

So, it looks like:

services:

  nginx:
      build: ./nginx/
      ports:
          - 80:80
      links:
          - php
      volumes:
          - ./appdata:/appdata

  php:
      build: ./php/
      expose:
          - 9000
      volumes:
          - ./appdata:/appdata
14
votes

The docker named volumes were removed starting from version docker-compose 3.

However, you can use extension-fields to avoid duplicating volumes source and prevent yourself from future typos:

version: '3.5'

x-services-volume:
  &services-volume
  type: bind
  source: ./appdata
  target: /appdata

services:

    nginx:
        build: ./nginx/
        ports:
            - 80:80
        links:
            - php
        volumes: *services-volume

    php:
        build: ./php/
        expose:
            - 9000
        # Use same way as for nginx if target override not needed.
        volumes:
            - <<: *services-volume
            target: /opt/target-override

NOTE: That feature available starting from version 3.4 file format.

5
votes

Previous answers helped me a lot (thanks!) but it took some more time to figure out how to set options to create a shared tmpfs volume (memory file system). I'm sharing it in the hope to make life easier for developers in the same situation.

An example showing only the relevant parts of docker-compose.yml:

version: '3'

volumes:
  shared-tmpfs:
    driver: local
    driver_opts:
      type: "tmpfs"
      device: "tmpfs"
      o: "size=256m,uid=1000"

services:
  nginx:
    volumes:
      - shared-tmpfs:/tmp/mytmpfs

  php-fpm:
    volumes:
      - shared-tmpfs:/tmp/mytmpfs

I use it to spare my SSD from heavy writes (building lot's of static html files) in development/watch mode.

You can read more about driver_opts in the official Docker docs here.