Moby: How to copy files into a named volume without an attached container?

Created on 29 Jul 2016  路  12Comments  路  Source: moby/moby

If I create a volume with:

docker volume create --name test-volume

I would like to then copy example.cfg into the volume. However, docker cp works with containers, not volumes.

Right now, I need to create a container that mounts the volume, copy the file in, then remove the container. Alternatively, I can inspect the volume and modify the filesystem directly. Is there a better way?

Most helpful comment

There's no need to _start_ the container, just _creating_ a container is enough;

docker container create --name dummy -v myvolume:/root hello-world
docker cp c:\myfolder\myfile.txt dummy:/root/myfile.txt
docker rm dummy

All 12 comments

That's the way to do it. For configuration files, you could consider using a bind-mount, or perhaps a volume driver that allows mounting configuration as a volume https://docs.docker.com/engine/extend/plugins/#/volume-plugins

I'm closing this issue, because this is a question, not a bug report, but feel free to continue the discussion

Thanks for the quick reply. Has there been a consensus decision not to support "copy into volume", or is this something that could be requested as a feature? If there has been a decision, what was the rationale?

Oh, yes, there is an open feature request, but it hasn't been decided on yet; see https://github.com/docker/docker/issues/18718.

Perfect, thank you.

Do you want to copy a file to a docker volume, but the volume doesn't have a container? I'll tell you how I do it.

Unfortunately, you do need a container. But, this is actually the lightest-weight method I have found so far.

Basic Idea

  1. Use docker run to start a dummy light-weight container and mount your volume.

    • The concept here is to use the alpine image and run some minimal service that doesn't exit. The lightest-weight image I can find is alpine linux (alpine), and the simplest command I can think of that doesn't exit is tail -f /dev/null.

    • Start this command with the -d option to _detatch_ and leave the dummy container running so that you can _reuse your existing shell_ to enter the next command. (which will be the docker cp command -- see step 2 below).

    • Use --rm so that when you stop the dummy container it will get removed automatically. This is a temporary container, so using automatic cleanup is a good habit and will prevent leaving a forgotten dummy container lying around.

    • Most importantly, use -v to mount the volume into the file system of the container. Choose any path that doesn't conflict with something in alpine. e.g.: /root

    • And finally, use the --name option to give the container a reasonable name to be used in steps 2 and 3 below. e.g.: dummy

  2. Use docker cp to copy the file into the container at the location you mounted the volume. In the example below, the file c:\myfolder\myfile.txt is copied into the volume.

    • You can repeat this step as many times as you like to copy more files.

    • You can copy from the local file system to the volume, or from the volume to the local file system as needed.

  3. Use docker stop to stop the dummy container. This will also cause docker to remove the container because you used the --rm option.

Step by Step Example

docker run -d --rm --name dummy -v myvolume:/root alpine tail -f /dev/null
docker cp c:\myfolder\myfile.txt dummy:/root/myfile.txt
docker stop dummy

You can also copy the other way (from the volume to the local file system).

docker cp dummy:/root/myfile.txt c:\myfolder\myfile.txt

_If there's a better way, I'd love to know what it is!_

There's no need to _start_ the container, just _creating_ a container is enough;

docker container create --name dummy -v myvolume:/root hello-world
docker cp c:\myfolder\myfile.txt dummy:/root/myfile.txt
docker rm dummy

Here's a one-liner that copies myfile.txt from current directory to my_volume:
docker run --rm -v $PWD:/source -v my_volume:/dest -w /source alpine cp myfile.txt /dest

@thaJeztah That's cool, thanks!

Now I'm wondering, is there an image that is lighter weight than hello-world? I can't just create a container running scratch.

So, I used the following Dockerfile to create a _nothing_ image.

FROM scratch
CMD
docker build -t nothing .

Now my steps are:

docker container create --name dummy -v myvolume:/root nothing
docker cp c:\myfolder\myfile.txt dummy:/root/myfile.txt
docker rm dummy

@wyckster
https://hub.docker.com/r/tianon/true/ is pretty light.
125 bytes

Here is my convenience script:
docker-volume-cp

#!/bin/bash
SOURCE=$1
DEST=$2

SOURCE_ARR=(${SOURCE//:/ })
DEST_ARR=(${DEST//:/ })


if [[ ${#SOURCE_ARR[@]} -eq 2 && ${#DEST_ARR[@]} -eq 1 ]]; then
        VOL=${SOURCE_ARR[0]}
        VOL_PATH=${SOURCE_ARR[1]}
        HOST_PATH=${DEST_ARR[0]}

        docker container create --name docker_volume_cp -v $VOL:/volume hello-world
        CMD="docker cp docker_volume_cp:/volume/$VOL_PATH $HOST_PATH"
        #echo "$CMD"
        $CMD
        docker rm docker_volume_cp

elif [[ ${#SOURCE_ARR[@]} -eq 1 && ${#DEST_ARR[@]} -eq 2 ]]; then
        VOL=${DEST_ARR[0]}
        VOL_PATH=${DEST_ARR[1]}
        HOST_PATH=${SOURCE_ARR[0]}

        docker container create --name docker_volume_cp -v $VOL:/volume hello-world
        CMD="docker cp $HOST_PATH docker_volume_cp:/volume/$VOL_PATH"
        #echo "$CMD"
        $CMD
        docker rm docker_volume_cp
else
        echo "Usage:"
        echo " volume --> host: $0 VOLUME:VOL_PATH HOST_PATH"
        echo " host --> volume: $0 HOST_PATH VOLUME:VOL_PATH"
fi

Explanation:

  • VOLUME is the name of the volume
  • VOL_PATH is the path of the file/directory that needs to be copied, relative to the root of the volume (which could be any unknown location inside the original container)
  • HOST_PATH is the path of the file/directory that needs to be copied, relative to the current host directory

Examples:

  • ./docker-volume-cp myvolume:. myvolume_dir (copy all contents of volume "myvolume" into a host directory "myvolume_dir")
  • ./docker-volume-cp myvolume_dir/. myvolume_copy:. (copy all contents of host directory "myvolume_dir" into volume "myvolume_copy", which is created if it does not already exist)
  • The above 2 commands virtually create a new volume copy of "myvolume"

Here's a one-liner that copies myfile.txt from current directory to my_volume:
docker run --rm -v $PWD:/source -v my_volume:/dest -w /source alpine cp myfile.txt /dest

@mvasin
How do copy from container to host in one line?

Was this page helpful?
0 / 5 - 0 ratings