Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to copy files into a named volume without an attached container? #25245

Closed
ToBeReplaced opened this issue Jul 29, 2016 · 18 comments
Closed

Comments

@ToBeReplaced
Copy link

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?

@thaJeztah
Copy link
Member

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

@thaJeztah
Copy link
Member

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

@ToBeReplaced
Copy link
Author

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?

@thaJeztah
Copy link
Member

Oh, yes, there is an open feature request, but it hasn't been decided on yet; see #18718.

@ToBeReplaced
Copy link
Author

Perfect, thank you.

@wyckster
Copy link

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!

@thaJeztah
Copy link
Member

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

@mvasin
Copy link

mvasin commented Feb 22, 2018

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

@wyckster
Copy link

@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

@TeamDman
Copy link

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

@dorintt
Copy link

dorintt commented Jan 7, 2020

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"

@janusznoszczynski
Copy link

janusznoszczynski commented Nov 26, 2020

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?

@tgallacher
Copy link

@janusznoszczynski, you should be able to use docker cp directly (or docker container cp, which is exactly the same).

Assume you're running a container named foobar and you want a file named myfile.txt located at /root, you can simply run:

docker cp foobar:/root/myfile.txt /root

This will copy the myfile.txt onto your host at /root/myfile.txt. This also works with the container id, etc., which can be found using docker container ls.

More details listed here: https://docs.docker.com/engine/reference/commandline/cp/

@debuglevel
Copy link

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

From volume to host (into the current directory!):
docker run --rm -v $PWD:/host -v docker-compose_monitoring-database:/volume -w /volume alpine cp monitoring.mv.db /host

@AWieclawski
Copy link

and what about remove copied files after all inner procedures inside docker volume?

@BraINstinct0
Copy link

Combined #25245 (comment), #25245 (comment), and #25245 (comment) for a quick(dirty?) script for copying file/folder into a Volume. Usage is . ./cp2dockervol.sh VOLUME_NAME SOURCE DESTINATION. (Volume will be created if absent; src will be checked if file exists; if docker is not running it'll also be checked.)
Though, I think @dorintt 's solution(#25245 (comment)) is way better for general usage. (Swapping out hello-world with tianon/true will be marginally faster in that case, too)

@kforner
Copy link

kforner commented Feb 23, 2023

I improved a bit the script from @dorintt to avoid container name collisions, for example if executed concurrently.
Thanks again @dorintt for this really useful script.

#!/bin/bash

# borrowed from https://github.com/moby/moby/issues/25245
# improved not to use global name docker_volume_cp for the temp container name

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]}

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

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

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

@psawa
Copy link

psawa commented May 19, 2023

Any news about the native support of this feature? All related issues seem to be closed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests