Skip to main content
  1. Posts/

How to find that one volume you're pretty sure you didn't lose

·440 words·3 mins·
Author
Nick Dumas
Table of Contents

What I expect you to know
#

This article is only relevant if you know about and use Docker volumes and have some fluency in bash. I’ll explain the code as I go, if it helps.

The Problem
#

Over the lifetime of a Docker host machine, it’s like that orphaned volumes ( and other detritus ) will accumulate over time. You might also find yourself fumbling a configuration and orphaning a volume yourself.

However we got here, we have a bunch of volumes and we need to know if any of them are important. In a perfect world, they’ll have decent names. We don’t live in a perfect world.

Make a list
#

Luckily, we have tools at our disposal to handle this. My thought process almost always starts with “Can I turn a list of the things I care about into a newline separated list?” If I can do that, I can start automating my troubleshooting.

Let’s start with docker volume ls. This is how we list volumes, but the default output isn’t quite what I’m looking for:

docker volume ls
DRIVER    VOLUME NAME
local     d35fce052fbce42b94b2f9b2957be0f77090fa006b1a192030eff07db3675af2
local     grafana-storage
local     plausible_db-data
local     plausible_event-data

This is human readable, and we could even do some slicing with cut or awk, but Docker gives us a flag that will take us exactly where we need to go: --format. Generally, Docker uses Go’s text/template library to back this feature, and more specifically, individual flags (usually) document the template verbs available. Here, we want Name.

docker volume ls --format "{{.Name}}"
d35fce052fbce42b94b2f9b2957be0f77090fa006b1a192030eff07db3675af2
grafana-storage
plausible_db-data
plausible_event-data

And now we have a newline separated list of volume names.

Process of elimination
#

The next part is fairly straightforward. We loop over this list and ask Docker to create a temporary container based on alpine, with a single volume mounted at /test/.

#! /bin/bash

# Newline separated list of volume names
volumes=$(docker volume ls --format="{{.Name}}")
for volume in $volumes; do
	# Help the user keep track of which volume they're exploring
	echo "Mounting $volume in a temporary image."
    docker run --rm -v $volume:/test/ -it alpine /bin/sh
done

Running this script should do something like this:

./cycle-volumes.sh
Mounting d35fce052fbce42b94b2f9b2957be0f77090fa006b1a192030eff07db3675af2 in a temporary image.
/ # ls /test/
clickhouse-server.err.log   clickhouse-server.log.1.gz  clickhouse-server.log.4.gz  clickhouse-server.log.7.gz
clickhouse-server.log       clickhouse-server.log.2.gz  clickhouse-server.log.5.gz  clickhouse-server.log.8.gz
clickhouse-server.log.0.gz  clickhouse-server.log.3.gz  clickhouse-server.log.6.gz
/ #
Mounting grafana-storage in a temporary image.
/ # ls /test
alerting          csv               file-collections  grafana.db        plugins           png
/ # exit
Mounting plausible_db-data in a temporary image.
/ # exit
Mounting plausible_event-data in a temporary image.
/ # exit

You can use bash to explore the volume and identify its contents, make note of which ones are which, and proceed accordingly.

Related

Too Many Games 2024 Retrospective
·1516 words·8 mins
In which I drive to Philadelphia and try to play a bunch of games.
Stamping Builds with Bazel
·667 words·4 mins
Versioning is a critical part of delivering software to users. With bazel, you can derive per-build values and inject them anywhere in your build process.
Non-mechanical Tabletop Gaming Fundamentals
·639 words·3 mins
A non-exhaustive list of tips and rules that elevate my tabletop gaming.