Hugo G
Hugo G

Reputation: 16506

How to re-mount a docker volume without overriding existing files?

When running Docker, you can mount files and directories using the --volume option. E.g.:

docker run --volume /remote ./local myimage

I'm running a docker image that defines VOLUMESs in the Dockerfile. I need to access a config file that happens to be inside one of the defined volumes. I'd like to have that file "synced" on the host so that I can edit it. I know I could run docker exec ..., but I hope to circumvent that overhead for only editing one file. I found out that the volumes created by the VOLUMES line are stored in /var/lib/docker/volumes/<HASH>/_data.

Using docker inspect I was able to find the directory that is mounted:

docker inspect gitlab-runner | grep -B 1 '"Destination": "/etc/gitlab-runner"' | head -n 1 | cut -d '"' -f 4

Output:

/var/lib/docker/volumes/9c233c085c36380c6c33035222c16e5d061368c5060cc81dda2a9a713a2b2b3b/_data


So the question is:

Is there a way to re-mount volumes defined in an image? OR to somehow get the directory easier than my oneliner above?


EDIT after comments by zeppelin I've tried rebinding the volume with no success:

$ mkdir etc

$ docker run -d --name test1 gitlab/gitlab-runner
$ docker run -d --name test2 -v ~/etc:/etc/gitlab-runner gitlab/gitlab-runner

$ docker exec test1 ls /etc/gitlab-runner/
certs
config.toml

$ docker exec test2 ls /etc/gitlab-runner/
# empty. no files
$ ls etc
# also empty

docker inspect shows correctly that the volume is bound to ~/etc, but the files inside the container at /etc/gitlab-runner/ seem lost.

Upvotes: 2

Views: 18776

Answers (3)

skroll
skroll

Reputation: 961

Try to avoid modifying data inside a container from the host directly, much nicer is when you wrap your task into another container that you then start with "--volumes-from" option when possible in your case.

Upvotes: 1

BMitch
BMitch

Reputation: 264156

$ docker run -d --name test1 gitlab/gitlab-runner
$ docker run -d --name test2 -v ~/etc:/etc/gitlab-runner gitlab/gitlab-runner

You've got two different volume types there. One I call an anonymous volume (a very long uuid visible when you run docker volume ls). The second is a host volume or bind mount that maps a directory on the host directly into the container. So each container you spun up is looking at different places.

Anonymous volumes and named volumes (docker run -d -v mydata:/etc/gitlab-runner gitlab/gitlab-runner) get initialized to the contents of the image at that directory location. This initialization only happens when the volume is empty and is mounted into a new container. Host volumes, as you've seen, only get the contents of the host filesystem, even if it's empty at that location.

With that background, the short answer to your question is no, you cannot mount a file inside the container back out to your host. But you can copy the file out with several methods, assuming you don't overlay the source of the file with a host volume mount. With a running container, there's the docker cp command. Personally, I like:

docker run --rm -v ~/etc:/target gitlab/gitlab-runner \
  cp -av /etc/gitlab-runner/. /target/.

If you have a named volume with data you want to copy in or out, you can use any image with the tools you need to do the copy:

docker run --rm -v mydata:/source -v ~/etc:/target busybox \
  cp -av /source/. /target/.

Upvotes: 2

gile
gile

Reputation: 5996

Not sure I understood your problem, anyway, as for the documentation you mention,

The VOLUME instruction creates a mount point with the specified name and marks it as holding externally mounted volumes from native host or other containers. [...] The docker run command initializes the newly created volume with any data that exists at the specified location within the base image.

So, following the example Dockerfile , after having built the image

docker build -t mytest .

and having the container running

docker run -d -ti --name mytestcontainer mytest /bin/bash

you can access it from the container itself, e.g.

docker exec -ti mytestcontainer ls -l /myvol/greeting
docker exec -ti mytestcontainer cat /myvol/greeting

Hope it helps.

Upvotes: 0

Related Questions