Files
werkator/docs/prs/2026-09-19-PR#80-prune-anonymous-volumes.md
ea19be0c7f
werkator build succeeded after 02:23
werkator/deploy build succeeded after 00:08
fix(init): the nightly Docker cleanup removes anonymous volumes too (#80)
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
2026-09-19 21:36:34 +02:00

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 ExecStart lines in order, and the unit's own filter run through sh against 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.md describes the step and how an existing host gets it: init --systemd rewrites the units, then systemctl --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.