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
61 lines
3.0 KiB
Markdown
61 lines
3.0 KiB
Markdown
> **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](../../src/test/kotlin/de/hoennig/werkator/commands/SystemdServiceFilesTest.kt) — 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.
|