docker system prune never touches a volume, so a Docker host collected 281 PostgreSQL data directories. Anonymous volumes are told by their 64-digit hex name, because docker volume prune spares named volumes only since Docker 23. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Co-authored-by: mhoennig <michael@hoennig.de> Reviewed-on: #80
3.0 KiB
WARNING: This document describes only the change applied in this PR. It may already be outdated once the next PR is merged. Historic PR-documentation is not maintained along with new PRs — treat it as a snapshot, not as current documentation.
The Problem
The Docker host vm4006 held 283 dangling volumes on 2026-09-19, 17.7 GB.
281 of them were anonymous, each a PostgreSQL data directory of about 45 MB.
The nightly werkator-docker-prune.timer had run every night and reported success.
The unit runs docker system prune -af, and that command never removes a volume without --volumes.
The flag was left out on purpose: the per-repository Gradle cache volumes have to survive the cleanup.
So nothing on the host ever removed a volume.
The volumes came from the repository's smoke test, which removes its throw-away database container with docker rm -f, without -v.
The image declares its data directory as a volume, so every build left one behind.
That is fixed in the repository, but a CI host should not depend on every build script getting this right.
Non-Goals
- Named volumes stay, whoever created them; a stale cache volume from before the rename is removed by hand.
- No pruning from inside Werkator; the cleanup stays a systemd unit of the host.
- No change to the timer.
The Scenarios
Feature: the nightly cleanup removes the volumes nobody named
Scenario#80.01: Anonymous volumes go, cache volumes stay
- Given dangling volumes on a Docker host, some named by Docker with 64 hex digits, one named
werkator-gradle-<repo> - When the nightly prune service runs
- Then the hex-named volumes are removed after the containers have been pruned
- And the Gradle cache volume is still there
- And a volume held by a running container is untouched, because it is not dangling
Verified by
- SystemdServiceFilesTest — the two
ExecStartlines in order, and the unit's own filter run throughshagainst a hex name, a cache volume name and a 65-digit name
The Solution
SystemdServiceFiles.pruneServiceContent gets a second ExecStart:
docker volume ls -q -f dangling=true | grep -Ex "[0-9a-f]{64}" | xargs -r docker volume rm.
The name is the criterion because it holds on every Docker version.
docker volume prune spares named volumes only since Docker 23; before that it takes every unused volume, and at 02:00 the Gradle caches are unused.
The com.docker.volume.anonymous label exists only since 23 as well.
The step is not prefixed with -: a volume that cannot be removed fails the unit, which is how the host says so.
Additional Changes
docs/deployment.mddescribes the step and how an existing host gets it:init --systemdrewrites the units, thensystemctl --user daemon-reload.- Version 1.21.3 with its release note.
Follow-up PRs
- None in this repository.
vm4006 needs the new version and one
init --systemd; its 281 volumes were removed by hand on 2026-09-19.