| name | linux-image-hygiene |
| description | Use when measuring or reclaiming Docker/Podman storage and scheduling safe cleanup on Debian/Ubuntu or RHEL-family hosts. Covers images, cache, networks, and authorised volume pruning; use linux-container-engine for engine setup. |
| license | MIT |
| metadata | {"portable":true,"compatible_with":["claude-code","codex"],"author":"Peter Bamuhigire","author_url":"techguypeter.com","author_contact":"+256784464178"} |
Container Image & Volume Hygiene
Distro support
Two-family skill. The prune commands are nearly identical between Docker and
Podman; the differences are storage location (Docker keeps everything under
/var/lib/docker; rootless Podman under ~/.local/share/containers) and that
on RHEL you usually drive Podman. The body below shows Docker on Debian/Ubuntu;
substitute per this matrix.
| Concept | Debian/Ubuntu | RHEL family |
|---|
| Disk usage report | docker system df | podman system df |
| Prune (safe: dangling + stopped) | docker system prune | podman system prune |
| Prune everything unused | docker system prune -a --volumes | podman system prune -a --volumes |
| Unused images only | docker image prune -a | podman image prune -a |
| Dangling images only | docker image prune | podman image prune |
| Unused volumes | docker volume prune | podman volume prune |
| Unused networks | docker network prune | podman network prune |
| Storage root | /var/lib/docker | /var/lib/containers (root) / ~/.local/share/containers (rootless) |
| Schedule | systemd timer (system) | systemd timer; rootless uses --user + linger |
RHEL-family notes: rootless Podman storage is per-user under
~/.local/share/containers/storage — a docker system prune as root will not
touch it; run podman system prune as the owning user. A scheduled prune for a
rootless user needs a --user timer plus loginctl enable-linger. See
../../docs/multi-distro/plan.md.
Use When
- A container host is filling its disk (
/var/lib/docker, container storage).
- Removing dangling images, stopped containers, unused volumes/networks, build cache.
- Setting up automatic, scheduled cleanup with a systemd timer.
Do Not Use When
- Installing or configuring the engine; use
linux-container-engine.
- Running or supervising containers; use
linux-container-deployment.
- General host disk triage outside containers; use
linux-disk-storage.
Required Inputs
| Artefact | Required? | Source | If absent |
|---|
| Engine, execution user, storage root, and pressure target | yes | Host inventory and filesystem metrics | Measure only; do not prune. |
| Object ownership and retention policy | yes for -a/volumes | Workload owners | Limit to dangling objects or stop. |
| Approved destructive scope and rollback/re-pull plan | mutation | Change approval | Produce a candidate list only. |
- The engine in use (Docker daemon vs rootless Podman) and whose storage to clean.
- How aggressive the prune may be (dangling-only vs
-a --volumes).
- For scheduling: the cadence and whether it is a system or rootless-user timer.
Capability Contract
Storage measurement and candidate listing are read-only. Every prune is destructive and requires explicit scope; --volumes requires separate confirmation from data owners. Scheduled cleanup requires authority to create and enable units.
Degraded Mode
Without engine access, return measurement commands only. If object ownership cannot be established, do not classify it as unused. If reclaim cannot be measured, report the result as unverified.
Decision Rules
| Choice | Action | Failure or risk avoided |
|---|
| Dangling versus all unused | Start with dangling; use -a only after reconciling stopped workloads and rollback images. | Deleting needed rollback artefacts. |
| Volumes | Exclude by default; prune only named approved volumes after backup/ownership checks. | Irrecoverable state loss. |
| Rootful versus rootless | Inspect each relevant user's storage separately. | Cleaning the wrong store. |
| Scheduled prune | Schedule only a conservative, logged scope with disk thresholds. | Unattended destructive cleanup. |
Workflow
-
Measure first with docker system df / podman system df.
-
Identify what is genuinely unused (dangling images, stopped containers, orphan volumes).
-
Prune from least to most aggressive; confirm before -a --volumes.
-
Optionally install a scheduled prune (systemd timer) and verify it ran.
-
Stop before any object whose owner or retention need is unresolved; recover deleted images by re-pulling recorded digests, while volumes require the separately proven backup restore path.
Quality Standards
- Always run
system df before pruning so the reclaim is measured, not guessed.
- Start with safe prunes; reserve
-a --volumes for hosts you fully understand.
- Volumes hold data — never auto-prune volumes on a stateful host without review.
Anti-Patterns
-
Pruning volumes by default. Fix: exclude them unless owners separately approve named targets.
-
Treating unused as ownerless. Fix: reconcile stopped workloads and rollback images.
-
Cleaning the wrong user store. Fix: record engine, rootful/rootless mode, and execution user.
-
Reporting estimated savings as reclaimed. Fix: compare pre/post engine and filesystem usage.
-
Scheduling aggressive cleanup silently. Fix: use conservative scope with logs, thresholds, and alerts.
-
Running docker system prune -a --volumes on a host with paused-to-investigate images, or with data-bearing volumes.
-
Scheduling an aggressive -a --volumes prune unattended on a DB/stateful host.
-
Cleaning root Docker storage and assuming rootless Podman storage was also freed.
-
Treating "unused" as ownerless. Correction: reconcile stopped stacks, rollback images, and named volumes with owners.
-
Reporting estimated savings as reclaimed. Correction: capture before/after filesystem and engine measurements.
-
Scheduling cleanup without logs or alerting. Correction: retain unit output and alert on failure or low space.
Outputs
| Artefact | Consumer | Acceptance condition |
|---|
| Prune plan | Host owner | Lists engine/user, exact candidate classes, exclusions, approvals, and commands. |
| Reclaim report | Capacity owner | Shows before/after engine and filesystem usage plus objects removed. |
| Timer evidence | On-call operator | Conservative scope, schedule, logs, next run, and failure status are verifiable. |
Evidence Produced
| Artefact | Acceptance |
|---|
| Reclaim evidence | Contains engine/user context, pre/post usage, candidate scope, approval, prune output, and timer status. |
Capture engine/user context, pre/post system df, filesystem free space, candidate list, approval for aggressive scopes, prune output, and timer status. Never call an unmeasured action successful.
Worked Example
For rootless Podman pressure, inspect the affected user's store, preserve images referenced by stopped rollback containers, prune dangling build artefacts only, and compare both Podman and filesystem bytes before and after.
- The disk reclaimed (before/after
system df).
- Exactly which objects were pruned (images/containers/volumes/networks/cache).
- Any scheduled timer installed and its next-run time.
References
This skill is self-contained. Every command below is a standard engine tool
— docker on Debian/Ubuntu, podman on the RHEL family (see the Distro
support matrix). The sk-* script is an optional convenience wrapper — never
required.
This skill owns disk reclamation. It does not own installing the engine
(linux-container-engine) or running containers (linux-container-deployment).
Measure before you prune
docker system df
docker system df -v
podman system df
RECLAIMABLE is the headline number — what a prune would free.
Prune scopes (least to most aggressive)
docker image prune
docker system prune
docker image prune -a
docker image prune -a --filter 'until=720h'
docker system prune -a --volumes
docker container prune
docker volume prune
docker network prune
docker builder prune
docker system prune -a deletes images not used by a running container —
including ones you stopped to investigate. Always run docker system prune
(no -a) first, and never auto-prune --volumes on a stateful host.
Podman is the same surface:
podman image prune -a
podman system prune
podman system prune -a --volumes
podman volume prune
[GROUNDING-GAP: image/volume/cache prune semantics and filters (until=, label=, dangling=) — grounded on Podman/Docker upstream docs; deepen with Container Security (Liz Rice)]
Scheduled prune (systemd timer)
The cleanest way to keep a host tidy is a *.timer + *.service pair that runs
a safe prune nightly. System scope (Docker / root Podman):
[Unit]
Description=Scheduled container image/cache prune
[Service]
Type=oneshot
ExecStart=/usr/local/bin/sk-container-prune --yes --schedule-safe
[Unit]
Description=Run container prune daily
[Timer]
OnCalendar=*-*-* 03:30:00
Persistent=true
[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now container-prune.timer
systemctl list-timers container-prune.timer
The sk-container-prune script below installs exactly this timer for you.
For rootless Podman use systemctl --user units plus
loginctl enable-linger <user>. Full detail (filters, storage layout, cron
alternative) is in
references/prune-and-scheduling.md.
[GROUNDING-GAP: systemd prune timer scheduling — grounded on Podman/Docker + systemd.timer upstream docs; deepen with Container Security (Liz Rice)]
Optional fast path (when sk-* scripts are installed)
Running sudo install-skills-bin linux-image-hygiene installs:
| Task | Fast-path script |
|---|
| Report reclaimable space, prune at chosen scope, optionally install the daily timer | sudo sk-container-prune |
This is an optional wrapper. The docker/podman prune commands above are the
source of truth.
Scripts
This skill installs the following scripts to /usr/local/bin/. To install:
sudo install-skills-bin linux-image-hygiene
| Script | Source | Core? | Purpose |
|---|
| sk-container-prune | scripts/sk-container-prune.sh | yes | Report reclaimable space (system df), then prune Docker and/or Podman at a chosen scope (safe / images / aggressive); asks before each destructive step; can install a daily systemd prune timer. Both families. |