25

I have tried out a docker image using the docker command line without specifying names for volumes. Now I found that I want to continue using this container/image but by defining the container in docker compose.

What is best practice for keeping the data from the anonymous/unnamed volumes and use them in the new container created by docker compose?

  • Can I somehow convert the unnamed into named volumes?
  • or should I create a new container with docker compose with named volumes and copy the data?
  • or any other option?
freiheitsnetz
  • 363
  • 1
  • 3
  • 7

5 Answers5

20

To summarize the workaround:

docker volume create --name <new_volume>
docker run --rm -it -v <old_volume>:/from:ro -v <new_volume>:/to alpine \
    ash -c "cd /from ; cp -av . /to"
docker volume rm <old_volume>

This method has the benefit of using the docker API. It uses a lightweight Linux image called alpine and its default shell, ash to run a file copy, cp -av from the old volume to the newly named volume.

CivFan
  • 306
  • 2
  • 9
  • 1
    as it is about moving data from to , wouldn't it be faster and space-conserving to use `mv` instead of `cp`? At least for volumes backed by `local` driver? – user228505 Feb 06 '21 at 11:34
  • @user228505 Good question. It would probably be faster, yes, and would probably be safe enough. But I like the idea of keeping the old volume read-only, until you're sure you're done with it. That said, if the volume had a couple TB or something, I would reconsider and probably use `mv`. – CivFan Feb 06 '21 at 15:57
  • 1
    Why to you use `docker run` to copy instead of just `cp /var/lib/docker/...` on the host? – Marc Jun 23 '21 at 12:04
  • @Marc Because using the docker API comes with far fewer caveats. – CivFan Jun 24 '21 at 19:24
8

You cannot currently rename existing volumes. (This is true whether they were previously named or were unnamed and had their names auto-generated.)

You can see this issue for more information on implementation of this feature, as well as add your "+1"/"Thumbs up" to let the developers know that you want it.

Without that, as far as I know, the only good way to do it is to create the new named volume and copy the data.

Moshe Katz
  • 3,053
  • 3
  • 26
  • 41
3

CivFan's answer didn't work for me as is, so I'm posting my solution here:

docker run --rm --volumes-from <container_name> -v <new_volume_name>:/to ubuntu bash -c "cd <source_dir>; cp -r . <dest_dir>/."

This copies the contents of source_dir in the container with container_name into dest_dir within the new volume new_volume_name.

To verify that it worked, you can list the contents of dest_dir with:

docker run --rm -i -v <new_colume_name>:/tmp ubuntu find /tmp
Sebastian
  • 131
  • 1
3

At the time of this writing the only option is to copy the data. The details may vary depending on your particular setup. The general list of steps to be performed is as follows:

  1. Stop and remove the source container to let the new volume be created at step 3.

    docker stop NAME
    docker rm NAME
    # or
    docker-compose stop SERVICE
    docker-compose rm SERVICE
    

    In some cases you might be able to postpone removing the source container, e.g. when switching from docker-compose anonymous volume to docker-compose named volume. In this case up would create the new volume. And you can proceed with copying the data. But even in this case stopping the container is advised to avoid data being changed as you copy them. And you've got to remove the source container for docker-compose to switch to the new volume (pay attention to the warnings).

    In some cases it's not really needed, e.g. when switching from standalone containers to docker-compose.

  2. Change docker-compose.yml if applicable.

  3. Start the new container for the new volume to be created.

    Standalone containers:

    docker run ...
    # or
    docker-compose up -d
    
  4. Stop the new container to avoid data being changed.

    docker stop ...
    # or
    docker-compose stop
    

    In case of migrating to e.g. a standalone container with a named volume you can just create the volume in place of starting/stopping the container.

  5. Copy the data.

    docker run --rm -v "SRC_VOLUME:/from" -v "DST_VOLUME:/to" \
        bash -c '
            shopt -s dotglob
            # rm -r /to/*  # e.g. pg might have populated the new volume
            cp -r /from/* /to
        '
    

    Where SRC_VOLUME, DST_VOLUME - volume name, id, or absolute path to a directory on the host.

    To list volumes attached to a container use:

    docker inspect CONTAINER --format '{{json .Mounts}}' | jq
    

    Where CONTAINER - container name or id.

  6. Start the new container.

    docker run ...
    # or
    docker-compose up -d
    
  7. Rejoice :)

In case you want to experiment with different setups, check out the following gist.

x-yuri
  • 1,845
  • 1
  • 22
  • 27
0

I found this looking for information about named volumes. I realize this is an old post but after reading it I did some research and found that it is possible at this time at least, to export the file system as a tarball, and import a tarball to image or as an image.

First export your containers' file system:

docker container export -o filename CONTAINER

And after / when creating a new container import the tarball to your filesystem:

docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]

If you specify an archive, Docker untars it in the container relative to the / (root).

You can also create untagged images with this little dandy:

docker import filesystem.tar
  • This doesn't work for volumes. "The docker export command does not export the contents of volumes associated with the container." https://docs.docker.com/engine/reference/commandline/export/ – CivFan Jan 26 '21 at 01:50