Skip to content

Keeping a persisted directory of data from a Docker container using volumes

Louis Maddox edited this page Sep 14, 2020 · 13 revisions

If a Docker container is run, the files modified during its session will not be persisted after the Docker process is shut down.

If you want to keep the changes made to its container file system locally, it can be desirable to use the host file system as 'storage' (i.e. to 'persist' the changes 'locally')

docker ps will list the processes of running docker containers with their CONTAINER_ID

This Q&A describes ways to "explore a docker container's file system"

  • Snapshotting
  • ssh
  • nsenter

More simply, since docker exec was introduced, you can docker exec <container> ls <dir path> (which seems preferable to creating a static image)

Much like virtual machines, you can mount the host's directories in a container and these will persist unlike the rest of the container's file system.

In my case I am spinning up the image coatwork/dockerimage:latest for the 2020 Combinatorial Optimisation summer school

docker run --rm -it -p 9001:9001 coatwork/dockerimage:latest

and this creates a persisted directory:

docker run --rm -it -v /home/louis/co/testing/files/:/jupyter/persist -p 9001:9001 coatwork/dockerimage:latest

I knew the working directory was /jupyter/ because I looked at the Dockerfile on Docker Hub (here) and read the line:

WORKDIR /jupyter

which is run before the Jupyter server is launched (see the sections on WORKDIR in Docker's documentation and note on best practices)

So passing /jupyter/persist as the volume location means it will be created as a directory alongside the notebook directories.

You can check the permissions for the directory with ls -ld and then convert these into the numeric code at chmod-calculator.com

sudo docker exec silly_johnson ls -ld "/jupyter/persist"

drwxr-xr-x 3 1000 1000 4096 Sep 14 12:34 /jupyter/persist

gives the permissions code for the directory ("silly_johnson" is the name of the active container found by sudo docker ps)

  • the three parts of the permissions are: owners, group members, other users

To make the directory writable by both host and container, you'd want to chmod +w it but that doesn't work with docker exec

  • Note that if jupyter/ is used as the volume location, not jupyter/persist (which was a location I invented for this purpose), then the container will mirror that empty directory and no notebooks appear there
    • this might have happened due to file permission mismatch?

To set permissions, it seems you have to set them before using the directory, as I'll now demonstrate.


The following section is a demo of what doesn't work, feel free to skip to the next line break

To step into the container running Jupyter, as shown here

docker exec -it xenodochial_kilby bash

(Above the container ID was silly_johnson but now it's become xenodochial_kilby)

This is a lot like ssh, and shows a command line from within the container's file system, running the bash shell.

www-data@85dd6fb1b423:/jupyter$ ls -ld ./*/
drwxr-xr-x 1 www-data www-data 4096 Aug 14 17:34 ./2020-09-14_monday/
drwxr-xr-x 1 www-data www-data 4096 Sep  9 22:15 ./2020-09-15_tuesday/
drwxr-xr-x 1 www-data www-data 4096 Aug 27 08:51 ./2020-09-16_wednesday/
drwxr-xr-x 1 www-data www-data 4096 Sep  7 10:05 ./2020-09-17_thursday/
drwxr-xr-x 1 www-data www-data 4096 Sep  9 17:58 ./2020-09-18_friday/
drwxr-xr-x 1 www-data www-data 4096 Sep  1 16:13 ./2020-09-22_tuesday/
drwxr-xr-x 1 www-data www-data 4096 Sep  7 11:14 ./2020-09-23_wednesday/
drwxr-xr-x 1 www-data www-data 4096 Sep  1 16:13 ./2020-09-24_thursday/
drwxr-xr-x 1 www-data www-data 4096 Aug 14 15:15 ./local/
drwxr-xr-x 3     1000     1000 4096 Sep 14 12:34 ./persist/

So now I'll try to change the permissions of the volume at persist/ to 777

www-data@85dd6fb1b423:/jupyter$ chmod 777 persist/
chmod: changing permissions of 'persist/': Operation not permitted

It's still not possible: you need to change it before using it.


To create a directory, you run docker volume create, however this defaults to storing the volume under /var/lib/docker/volume/ whereas I want to store it at /home/louis/co/testing/files/.

To specify a custom location, you need to pass the -o or --opt flag to docker volume create, and then set one of the settings to the unix mount tool (which is the "driver" managing volumes here).

It's not made very clear how this is derived from mount exactly (docker's docs are not friendly, frustratingly, and just say that you can find "the complete list of options" in the man pages for mount) but:

--opt device=/home/louis/co/testing/files/

seems to be the way to specify a custom location in this way

docker volume list will show any volumes created, so now I'll try to create a docker volume with custom permissions

So the command would be something like

docker volume create --opt device=/home/louis/co/testing/files/ persistent_files

It says I need to specify a type (this isn't documented!)

So if I try to go back to the start and create a test volume:

docker volume create test_vol
docker volume inspect test_vol

[
    {
        "CreatedAt": "2020-09-14T15:46:26+01:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/test_vol/_data",
        "Name": "test_vol",
        "Options": {},
        "Scope": "local"
    }
]

So there's nothing to go off in the options for a standard/template volume. Not very useful.

Since Linux uses ext4 filesystems, I'd think type=ext4 might work

docker volume create --opt type=ext4 --opt device=/home/louis/co/testing/files/ persistent_files

It worked!

Docker doesn't point this out exactly but the mount options for ext4 filesystems are in the ext4 man pages

Importantly, no directory has yet been created at /home/louis/co/testing/files/

So now we change the command which was previously:

docker run --rm -it -v /home/louis/co/testing/files/:/jupyter/persist -p 9001:9001 coatwork/dockerimage:latest

to:

docker run --rm -it -v persistent_files:/jupyter/persist -p 9001:9001 coatwork/dockerimage:latest

but this gives the error:

docker: Error response from daemon: error while mounting volume '/var/lib/docker/volumes/persistent_files/_data': failed to mount local volume: mount /home/louis/co/testing/files/:/var/lib/docker/volumes/persistent_files/_data: no such file or directory.

I interpret this to mean I need to create the directory ~/co/testing/files/ beforehand, and I'll set the permissions to the most permissive possible:

mkdir ~/co/testing/files/
chmod 777 ~/co/testing/files/

This time I get an error saying the directory is not a "block device"

docker: Error response from daemon: error while mounting volume '/var/lib/docker/volumes/persistent_files/_data': failed to mount local volume: mount /home/louis/co/testing/files/:/var/lib/docker/volumes/persistent_files/_data: block device required.

Clone this wiki locally