How to remove unnamed volumes when docker compose down? - docker

I have a docker-compose file which describes several services. All services have volumes attached to them, however only one has the volume named. When I run docker compose down I want to automatically delete the not named volumes while at the same time create all volumes that are missing.
services:
service1:
image: some/image:1
volumes:
- named-volume:/home/user1
service2:
image: some/image:2
#volumes: not declared volumes that are named automatically with a hash
volumes:
named-volume:
name: volume-for-service1
The first time I run docker compose up I want to automatically create all volumes (named and unnamed) and when I run docker compose down I want that unnamed volumes to be deleted while the named one (volume-for-service1) to be preserved. Next time I run docker compose up it should only create the unnamed volumes as the named one already exists.
I have tried:
docker compose down -v which removed no volume
docker compose down --remove-orphans which removed no volume
docker compose down --rmi local which removed no volume
docker-compose down -v which removed the named volume
docker-compose down --remove-orphans which removed no volume
docker-compose down --rmi local which removed no volume
OS: Windows 10 x64
I don't quite get it. What command should I run to achieve desired results?

Try using --renew-anon-volumes flag when bringing up the services
and use --volumes when bringing down the services
> docker-compose --renew-anon-volumes up
> docker-compose --volumes down
Refer the docker compose documentation
-V, --renew-anon-volumes Recreate anonymous volumes instead of retrieving
data from the previous containers.
-v, --volumes Remove named volumes declared in the `volumes`
section of the Compose file and anonymous volumes
attached to containers.
https://docs.docker.com/compose/reference/down/

To prevent removing named volumes, you should define them as external in the config file:
volumes:
volume-for-service1:
name: volume-for-service1
external: true
But you have to initially create them outside the config file somewhere else, either through:
docker volume create volume-for-service-1
or in a separate config file.
Reference: https://docs.docker.com/compose/compose-file/#external-1

I'm not aware of a way to remove unnamed volumes automatically, but you can match its hash and remove it with a small script.
To reuse your docker-compose.yml example, first you get the container name given the service name with:
docker-compose ps service2 # this is the one with unnamed volume in your example
Output could be something like:
NAME COMMAND SERVICE STATUS
project-service2-1 "docker-entrypoint.s…" service2 exited (0)
Then using the container name you can find its unamed volume hash:
docker inspect -f '{{ (index .Mounts 0).Name }}' project-service2-1
Now before deleting the volume you need to bring the container down or the volume would be in use.
docker-compose down
docker volume rm $volume # replace the "volume" var with the inspect output
Now that we saw the steps, let's try to make it a little script (slightly adjusted):
service_name=service2 # set the variable accordingly
container_id=$(docker-compose ps $service_name --quiet)
volume_name=$(docker inspect -f '{{ (index .Mounts 0).Name }}' $container_id)
docker-compose down
docker volume rm -f $volume_name

Related

How to write a script which can run the creation of Docker volumes in one command

In my Docker environment I have always to run the command to create volumes manually like
docker volume create --name= ...
I would like a way to speed up this process with a script shell which could help me to run at once.
If I could see a possible solution would be great as I have many volumes to create manually
A possible solution would be to use docker-compose and have a docker_compose.yml file composed only of volumes but no services:
version: "3.8"
volumes:
logvolume01: {}
logvolume02: {}
logvolume03: {}
When run, this creates the volumes accordingly:
$ docker-compose up
Creating volume "docker_logvolume01" with default driver
Creating volume "docker_logvolume02" with default driver
Creating volume "docker_logvolume03" with default driver
Attaching to
$ docker volume ls
DRIVER VOLUME NAME
local docker_logvolume01
local docker_logvolume02
local docker_logvolume03
If you need a more complex set of options while creating your volumes, you can find them in the documentation.
Just a little quirk to note here: per default, when you are using docker-compose, the volumes will be prefixed with the name of the folder you are in, this is done by Docker so there is no collision between different Docker projects.
This is the reason why, in the example above, the volumes are starting with docker_, because the folder I am in, is called docker.
To fix this, just give a name to your volumes:
version: "3.8"
volumes:
logvolume01:
name: logvolume01
logvolume02:
name: logvolume02
logvolume03:
name: logvolume03
Running this modified version gives:
$ docker-compose up
Creating volume "logvolume01" with default driver
Creating volume "logvolume02" with default driver
Creating volume "logvolume03" with default driver
Attaching to
$ docker volume ls
DRIVER VOLUME NAME
local logvolume01
local logvolume02
local logvolume03

Remove a single named volume with docker-compose?

Is this possible from docker-compose - or do I have identify the volumes location and delete them?
I can only find functionality to delete ALL the volumes associated with the docker-compose.yaml config file.
Compose can only remove all volumes defined in a yml file, or none
$ docker-compose down -v
If you don't want to investigate which volumes are used for the current compose file and remove them with docker volume rm X, then create a cutdown compose file that only lists the volumes you want to remove
docker-compose.yml
version: "2.1"
volumes:
one:
two:
three:
docker-compose-cleanup.yml
version: "2.1"
volumes:
two:
Then you can act on different sets depending on the compose file
$ docker-compose up
Creating volume "composevolumes_three" with default driver
Creating volume "composevolumes_two" with default driver
Creating volume "composevolumes_one" with default driver
Attaching to
$ docker-compose -f docker-compose-cleanup.yml down -v
Removing volume composevolumes_two

Docker container has volumes that aren't defined anywhere

I had a container running from an image, sebp/lighttpd, that had a volume mounted on it at /var/www/localhost. In my docker-compose file, I changed the config for that service to
build:
context: web/
image: myproject-web
Where neither the dockerfile at web/Dockerfile nor its from: image (bistenes/lighttpd) have any volumes defined. I ran docker-compose build and then docker-compose up, but the new container still has the old volume mounts defined, wiping the data I'm trying to COPY into /var/www/localhost when the container runs.
See this issue, which concludes with "It's not a bug, it's a feature!"
The issue indicates that docker-compose rm will do the trick.
I used docker inspect ${CONTAINER} to find the volume IDs, did docker rm ${CONTAINER}, then docker volume rm ${VOLUMES}.

Is there a way to tag or name volume instances using docker compose?

When using docker compose, I find a lot of volume instances:
› docker volume ls
DRIVER VOLUME NAME
local 4a34b9a352a459171137aac4c046a83f61e6e325b1df4b67dc2ddda8439a6427
local 6ce3e52ea363441b2c9d4b04c26b283d8b4cf631a137987da88db812a9a2d223
local a7af289b29c833510f2201647266001e4746e206128dc63313fe894821fa044d
local fb09475f75fe943671a4e73d76c09c27a4f592b8ddf62224fc4b20afa0095809
I'd like to tag or name them, then reuse them if possible rather recreating them each time.
Is that possible?
Those are anonymous container volumes that happen when you define a volume without a name or bind it to a host folder. This may be with the VOLUME definition in your Dockerfile, a docker run -v /dir ... rather than name:/dir, or a volumes entry in your docker-compose.yml with only the directory. An example of a compose file that does a named mount is:
version: '2'
volumes:
my-vol:
driver: local
services:
my-container:
image: my-image
volumes:
- my-vol:/container/path
Once the anonymous volume has been created, there's no easy way to rename it. Easiest solution is to mount the anonymous volume along with the your target named volume and do a copy, e.g.:
docker run -v 123456789:/source -v my-vol:/target --rm \
busybox cp -av /source/. /target/
Where 123456789 is the long name of your anonymous volume.

Docker named volumes vs DOC (data-only-containers)

Up to recent version of Docker (v1.10), we were thought that we can use DOC: data-only containers. So I would create such DOC (based on e.g. busybox) and use --volumes-from to link it to my container. You can still read about this in Docker documentation.
With new version of docker, it is said that instead of DOC we should use named volumes. Here is an example of docker-compose.yml:
version: '2'
services:
elasticsearch:
image: elasticsearch:2.2.0
command: elasticsearch -Des.network.host=0.0.0.0
ports:
- "9201:9200"
volumes:
- "es-data:/usr/share/elasticsearch/data"
volumes:
es-data:
Here we created and use named volume es-data.
There is still not much documentation on this new feature. I am asking:
Can we replace DOC with named containers? How long volume is persisted? What if I remove the container that is using it?
How can we e.g. backup now? Previously, I could docker run --rm --volumes-from es-data ... and then tar it.
Can we replace DOC with named containers?
In many cases, yes, named containers will be a better option.
How long volume is persisted? What if I remove the container that is using it?
If you remove the container, the volume will still be there. The only way to remove the volume is to use docker-compose down -v or docker volume rm <volume name>.
How can we e.g. backup now? Previously, I could docker run --rm --volumes-from es-data ... and then tar it.
Instead of --volumes-from, you can use --volume=<volume name>.
Note that volumes created by docker-compose are always prefixed with the project name, so if you use it with a docker command the full name is actually <project_name>_es-data.

Resources