There are seemingly similar questions here (docker-compose volumes_from equivalent with version 3, How to replace volumes_from in docker-composer v3) but I don't think they answer the question (or at least I don't understand how the answers solve the problem). So let me try to ask again, very specifically.
I have this v2 docker-compose.yml:
version: '2'
services:
full-tests:
volumes:
- ..:/opt/project
- ../../../ext-libs:/opt/ext-libs
- ./third-mapping:/opt/third
unit-tests:
volumes_from: full-tests
The point is that the set of volumes is defined once and I can easily reuse them using volumes_from
.
How would you rewrite this in v3?
To answer your question - its impossible with v3 - see the section below. v3 shall not be used as a successor ( also a official statement by docker ) it shall be used in "swarm cases".
nevertheless, what you do should do is using named volumes.
You can combine it with host-mount volumes like this
docker volume create --name volume1 -o type=none -o device=/home/$USER/projects/01 -o o=bind
You can simplify this using the long-syntax introduced in 3.2: https://docs.docker.com/compose/compose-file/#long-syntax-2 so you can define the named volume + bind on the host in the docker-compose file
example:
services:
full-tests:
volumes:
- type: volume
source: ../
target: /opt/project
- type: volume
source: ../../../ext-libs
target: /opt/ext-libs
or in short as you had
services:
full-tests:
volumes:
- ../:/opt/project
- ../../../ext-libs:/opt/ext-libs
What you cannot do though, putting the long-syntax under the top-level "volumes" definition to give that volume a name and reused it in the volumes section in the services - that is not possible. To do so, you would use a
volumes:
project:
external: true
third-party:
external: true
And then use the "docker volume create" syntax on the cli to create those volumes with a bind option, as outlines above
but you will never get what volumes_from was doing for you here
There is no equivalent of volumes_from in v3, since v3 is not a successor of v2, its an alternative - please see my comment and the sources here https://github.com/rancher/rancher/issues/3316#issuecomment-310889283
To sum it up - volumes_from and volumes have an overlap in the case volumes_from was just used the wrong way / in the wrong field.
a) If you want data to be persisted across stack upgrades ( down + up ), you pick named volumes - and now, if 2+ services needs to share this, just mount this named volume using volumes:
.
b) If you though, do not want the data to persist over stack upgrades ( e.g. because its source code and the image actually includes an upgrades this ) as a in a usual application + httpd/proxy scenario, you will create a anon-volume for this e.g. /var/www
in the Dockerfile using Volume /var/www
and then use volumes_from to mount it in the httpd
service.
the main point with b is, that on stack upgrades, the anon volume will be removed ( `docker-compose down removes anon containers, but not named ones ) and thus the upgrade works as expected, you have a new codebase
Trying to do the same with named volumes will give you a huge suprise on the first upgrade, since the code is on a named volume and that will overlay the codebase on the "fresh" image / new container, thus you will run on the old codebase after the upgrade.
You could use extension fields to keep the code short but it isn't quite the same as volumes_from
. For example:
version: '3.7'
x-volumes:
&my-volumes
- ..:/opt/project
- ../../../ext-libs:/opt/ext-libs
- ./third-mapping:/opt/third
services:
full-tests:
volumes:
*my-volumes
unit-tests:
volumes:
*my-volumes
I got docker-compose version 3 working with unison. Basically had to replace "volumes_from" and create a global "volumes" declaration.
version: "3"
services:
unison:
container_name: xxx_unison
image: onnimonni/unison
environment:
- UNISON_DIR=/var/www/$DOCKER_WEB_DOMAIN/htdocs/
- UNISON_USER=www-data
- UNISON_UID=1000
- UNISON_GID=1001
volumes:
- unison_file:/var/www/$DOCKER_WEB_DOMAIN/htdocs/
networks:
- frontend
ports:
- "5000:5000"
database:
container_name: xxx_database
image: percona
depends_on:
- unison
environment:
- MYSQL_ROOT_PASSWORD=xxx
- MYSQL_DATABASE=xxx # Assign a database to be created on container first load
volumes:
- ./mysql/import:/docker-entrypoint-initdb.d
- ./mysql/data/:/var/lib/mysql/
- ./logs:/var/log/mysql
- ./mysql/conf:/etc/mysql/conf.d
ports:
- "3306:3306"
networks:
- frontend
web:
container_name: xxx_web
image: ubuntu
depends_on:
- unison
volumes:
- ./nginx/ssl/:/etc/nginx/ssl/
- ./logs/:/var/log/nginx
- ./shell/run.sh:/run.sh
- unison_file:/var/www/$DOCKER_WEB_DOMAIN/htdocs/
ports:
- "80:80"
- "443:443"
networks:
- frontend
env_file:
- ./.env
networks:
frontend:
volumes:
unison_file: