CHRISTOPHER SHROBA

Browsing all Docker Volumes at Once

While using docker, you may find you want to quickly inspect the contents of one or more volumes, for example to figure out what’s going on inside it, back up data, tail log files, rearrange files, or add a file from the host system. Here’s a handy one-liner that makes all that quite simple, followed by an explanation and some improvements that are possible and easy:

1
docker run --rm -ti $(docker volume ls --format='-v {{.Name}}:/vols/{{.Name}}') -v $HOME:/host_home bash

This will mount all your volumes as directories named after each volume, in the /vols directory of the container it will launch, and will mount the $HOME directory of your host system into /host_home on the container, which makes it easy to copy files between host and volumes.

An Explanation

Let’s build up that command step by step. First we list all the volumes on the system:

1
2
3
4
5
6
$ docker volume ls
DRIVER VOLUME NAME
local 79ce24fa46b631ee773e74a13391a85f92fac70ebad4030bcd3d10e1833e6151
local my_project-postgres_pgdata
local e8021448d4e84864c834f3569efd646aab08c8cfcd862cec2a7a23450e952d66
local my_other_project_postgres_pgdata

We want to get just the names of these volumes, and mount those into a docker container. Since the typical syntax for mounting a volume into a container is docker run -v <Volume Name 1>:<Mount Path 1> -v <Volume Name 2>:<Mount Path 2> <Image name> (etc.), we will write a command that generates that list of volume mounts, then include that in the docker run command using command substitution.

If we had volumes called FooVolume and BarVolume, we’d want our docker run flags to look something like -v FooVolume:/vols/FooVolume -v BarVolume:/vols/FooVolume. Luckily, most docker commands take a --format argument that lets us tweak the output to look exactly how we want it, so we can get that format using this syntax:

1
2
3
4
5
$ docker volume ls --format='-v {{.Name}}:/vols/{{.Name}}'
-v 79ce24fa46b631ee773e74a13391a85f92fac70ebad4030bcd3d10e1833e6151:/vols/79ce24fa46b631ee773e74a13391a85f92fac70ebad4030bcd3d10e1833e6151
-v my_project-postgres_pgdata:/vols/my_project-postgres_pgdata
-v e8021448d4e84864c834f3569efd646aab08c8cfcd862cec2a7a23450e952d66:/vols/e8021448d4e84864c834f3569efd646aab08c8cfcd862cec2a7a23450e952d66
-v my_other_project_postgres_pgdata:/vols/my_other_project_postgres_pgdata

Then we can just add a -v $HOME:/host_home to mount the host system’s home folder (aka ~) into the container for easy copying between the host and the volumes. This can be left out if you don’t need this functionality, but I like to add it so there’s just one common command I use every time I’m browsing my volumes.

This gives us all the pieces we need to start browsing our volumes. We use command substitution to include all the volume mount flags, and -it so that our shell is interactive:

1
docker run --rm -ti $(docker volume ls --format='-v {{.Name}}:/vols/{{.Name}}') -v $HOME:/host_home bash

Installing our favorite utilities to make life easier

We could use the command above and call it a day, but there are several utilities Iike to have access to when I’m messing around with my volumes, such as ncdu (for quickly viewing directory sizes and the larges files), tree (for viewing all the files in a directory at a glance), vim (for file editing), and zsh with Oh My Zsh (just shell personal preference!).

We can make our own docker image to use which has all these things, or whatever tools you prefer, installed. Create a new directory wherever you keep projects:

1
2
3
mkdir data-volume-explorer
cd data-volume-explorer
vim Dockerfile

and create a Dockerfile that sets up your environment how you like it. Here’s my current Dockerfile:

1
2
3
4
5
6
7
8
9
FROM alpine:latest

RUN apk add zsh curl tree git ncurses ncdu
RUN curl -Ls install.ohmyz.sh | sh

COPY ./zshrc /root/.zshrc

WORKDIR /vols/
ENTRYPOINT zsh

This copies in my .zshrc file as well, which I won’t include here, but does contain the following lines to put a yellow “Docker Volumes” in my prompt (so I remember that I’m in a container and not on my host system) and show all the volume names right when the container starts (since otherwise I would run ls right away anyway):

1
2
3
4
PS1="$(tput setaf 3)Docker Volumes $(tput sgr0)$PS1"

echo Volumes:
ls

Once you have your Dockerfile in good condition, build and tag it:

1
docker build -t docker-volume-explorer .

and now you can use it as your docker image to run instead of bash:

1
docker run --rm -ti $(docker volume ls --format='-v {{.Name}}:/vols/{{.Name}}') -v $HOME:/host_home docker-volume-explorer
OLDER > < NEWER