46

With Docker Compose v1.6.0+, there now is a new/version 2 file syntax for the docker-compose.yml file. The changes include a separate top level key named volumes. This allows to "centralize" volume definitions in one place.

What I am trying to do is to name volumes in there and have a single volume reference multiple path on my local host disk. The following is an example, throwing an exception with a Traceback that ends with

AttributeError: 'list' object has no attribute 'items'

Example docker-compose.yml:

version: '2'

services:
  db:
    image: postgres
    volumes:
      - database:/var/lib/postgres/data

  php:
    image: php-fpm:5.6
    volumes:
      - phpconf:/etc/php/conf.d

  namedvolume:
    container_name: namedvolume
    build: ./Docker/Testvolume
    volumes: 
      - ./Docker/Testvolume/shareme

volumes:
  database:
    - ./Docker/Postgres/db:ro
    - ./Docker/Postgres/ini
  phpconf:
    - ./Docker/PHP-FPM/conf
  singledir: ./Docker/foo
  completemap: ./Docker/bar:/etc/service/conf.d
  - namedvolume:/etc/service/conf.d # < this was a separate attempt w/o the other keys
  … ?

So far I read through all the Docker Compose docs master-branch Volume configuration reference, the Docker Compose docs Volume/Volume-Driver reference and looked through GitHub examples to find the correct syntax that is expected. It seems no one is already using that (GitHub) and the documentation is far from being complete (docker.com). I also tried to build a separate volume as service and reference it in volumes, but that does not work as well. Any idea on how to this syntax is supposed to look like?

Derek Adair
  • 137
  • 1
  • 8
kaiser
  • 1,251
  • 1
  • 16
  • 24

4 Answers4

42

Purpose of the volumes key

It is there to create named volumes.

If you do not use it, then you will find yourself with a bunch of hashed values for your volumes. Example:

$ docker volume ls 
DRIVER              VOLUME NAME
local               f004b95d8a3ae11e9b871074e9415e24d536742abfe86b32ffc867f7b7063e55
local               9a148e167e1c722cbdb67c8edc36f02f39caeb2d276e9316e64de36e7bc2c35d

With named volumes, you get something like the following:

$ docker volume ls
local               projectname_someconf
local               projectname_otherconf

How to create named volumes

The docker-compose.yml syntax is:

version: '2'

services:
    app:
        container_name: app
        volumes_from:
            - appconf
    appconf:
        container_name: appconf
        volumes:
            - ./Docker/AppConf:/var/www/conf

volumes:
    appconf:

networks:
    front:
        driver: bridge

This something like above shown named volumes.

How to remove volumes in bulk

When you have a bunch of hashes, it can be quite hard to clean up. Here's a one-liner:

docker volume rm $(docker volume ls |awk '{print $2}')

Edit: As @ArthurTacca pointed out in the comments, there's an easier to remember way:

docker volume rm $(docker volume ls -q)

How to get details about a named volume

Now that you do not have to look up hashes anymore, you can go on it and call them by their … name:

docker volume inspect <volume_name>

# Example:
$ docker volume inspect projectname_appconf

[
    {
        "Name": "projectname_appconf",
        "Driver": "local",
        "Mountpoint": "/mnt/sda1/var/lib/docker/volumes/projectname_appconf/_data"
    }
]

Sidenote: You might want to docker-compose down your services to get a fresh start before going to create volumes.

In case you are using Boot2Docker/ Docker Machine, you will have to docker-machine ssh and sudo -i before doing a ls -la /mnt/… of that volume – you host machine is the VM provisioned by Docker Machine.

EDIT: Another related answer about named volumes on SO.

kaiser
  • 1,251
  • 1
  • 16
  • 24
  • 1
    very good answer. cheers. Cleared up a lot coming back to find new docker-compose volumes. – Derek Adair Nov 19 '16 at 15:30
  • Where did you find these? seems a lot more thourough than the docker docs? – Derek Adair Nov 19 '16 at 15:32
  • @DerekAdair Try and error and finally reading Dockers core code on Github. – kaiser Nov 20 '16 at 12:03
  • Very nice, you may consider submitting this to the official documntation if its not already in the works. – Derek Adair Nov 22 '16 at 19:49
  • 1
    @DerekAdair Thanks, but as you can read in the stats in the upper left, this answer is well referenced in the Google search engine result pages on this topic. – kaiser Nov 22 '16 at 21:45
  • 1
    Instead of `$(docker volume ls |awk '{print $2}')` you can use `$(docker volume ls -q)` Not only is this simpler, it doesn't print "VOLUME" on the first line. – Arthur Tacca Jan 11 '17 at 10:32
  • 2
    This is not correct; this doesn't do what it makes it seem like it does. `volumes_from` is to *inherit* the list of volumes from another container. To use a named volume, you use the service-level syntax `- NAME:DEST`, and set the path in the top level `volumes` key. What this example does (at the time of writing this) is make a standard volume in *addition* to a named volume, and the named volume is simply not used. – trevorj May 09 '17 at 05:22
  • volumes_from is no longer available in the 3.0 syntax, any alternative? – Roman Gaufman Aug 14 '17 at 15:41
15

The way I understand it, you can use the global volumes: section to

  • define a volume name
  • make an named volume available under a different volume name
  • specify a driver and driver options for a named volume

Volumes in the global section will be auto-created unless you specify external: true. You will still need to tell each service in its volumes: section where to mount that volume.

Here's a very simple example:

version: '2'
volumes:
  project:
services:
  one:
    volumes:
      - project:/bar
  two:
    volumes:
      - project:/foo

The global volumes: entry for project will cause a named volume project to be created. It then gets mounted as /bar in service one, and as /foo in service two. Both services share the volume's data and can read/write it.

I don't think that what you are trying to do is possible (turning multiple paths into a single volume, and with different r/w flags). If it is possible, then probably by finding a way to create a named volume with these properties through some other means and then adding it as an external volume:

volumes:
  mymagicvolume:
    external: true
Ivan Aracki
  • 103
  • 4
puzzle
  • 251
  • 1
  • 4
  • 1
    Already upvoted, but just today found time to get around it and added an extended data. Thanks for all your help! Question: As you name the volume `project` and then reference it as `project:/bar`, where are `project` paths actually defined? – kaiser Apr 09 '16 at 14:21
  • docker-compose will automatically create them as named volumes under /var/lib/docker/volumes/volumename – JamesCW Jun 09 '16 at 20:17
  • Sorry, still don't understand where does docker get a path for `project:` alias? How does docker know if I want to share, say `./some_folder/some_subfolder/yet_another_subfolder` to the `one:` and `two:` containers? – Alex Lomia Apr 06 '17 at 08:49
  • In that case it is "project:" under the top-level volumes: section – Balint Bako Apr 19 '17 at 15:16
5

Check out Version 2 for example, also Volume configuration reference:

My example: (Version 1)

$ tail -4 docker-compose.yml 
  volumes:
    - ./etc/nginx/conf.d:/etc/nginx/conf.d:ro
    - ./var/log/nginx:/var/log/nginx:rw
    - ./var/www/html:/var/www/html:rw
$ 
alexus
  • 12,342
  • 27
  • 115
  • 173
  • 1
    This is exactly what I linked in the question and therefore does not answer my question. Would you mind posting an example of how to map different directories from the host as a named volume to multiple services? – kaiser Mar 02 '16 at 22:16
  • my link _IS_ different, it points to `Version 2` section of document) – alexus Mar 02 '16 at 22:21
  • My bad. I simply forgot to link that one as well. When you look at the YML stuff in the question, you can see that I clearly tried to get around using the separate top level `volumes` key – which I didn't, hence the question. What I don't get is what the `docker-compose.yml` part with version 1 syntax is meant to explain me. – kaiser Mar 02 '16 at 22:32
5

I think what you're trying to do is roughly the same as seen here. In short: it's currently not possible to create a named volume that refers to a mount point on the host. You can create a named volume to share data between containers, but the data will only exist in the volume itself, and disappear when you delete the volume.

Mounting named volumes has been proposed, but unfortunately it won't be added to the core in the near future. However, it is possible by using a docker plugin named local-persist.

Sander
  • 151
  • 1
  • 3
  • 3
    _Mounting named volumes_ [now is a thing](https://github.com/docker/docker/issues/19990#issuecomment-248955005) … since 1.11 or 1.12. – kaiser Oct 13 '16 at 20:33