#!/usr/bin/env bash # Reclaim Docker's unused cache so host storage stays bounded. # # Modes: # (default) — gentle, age-windowed (keeps rollback + rebuild speed): # - BuildKit cache older than 72h, hard-capped at 4 GB (Debian /pnpm store # is shared across builds; everything newer speeds up rebuilds). # - Images referenced by NO container and older than 7 days. # - Containers stopped for more than 24h. # --force — emergency mode ("never let the disk max out"): drops every age # window and reclaims all unused bytes Docker can free: # - ALL unreferenced build cache, # - ALL unreferenced images (no 7-day grace), # - ALL stopped containers. # Trade-off: waiting rebuilds re-fetch deps/images later. # # Volumes are NEVER pruned in either mode: mariadb-turbo-data is a database. # Idempotent; exits 0 when Docker is unavailable. set -Eeuo pipefail DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" LOG_DIR="${LOG_DIR:-$DIR/logs}" mkdir -p "$LOG_DIR" LOG_FILE="$LOG_DIR/docker-prune.log" now() { date '+%Y-%m-%d %H:%M:%S'; } FORCE=0 if [[ "${1:-}" == "--force" ]]; then FORCE=1 fi command -v docker >/dev/null 2>&1 || { printf '[%s] docker CLI unavailable; nothing to prune\n' "$(now)" >>"$LOG_FILE" exit 0 } printf '\n[%s] === docker prune start%s ===\n' "$(now)" "$( (( FORCE )) && printf ' (FORCE)' )" >>"$LOG_FILE" docker system df >>"$LOG_FILE" 2>&1 || true if (( FORCE )); then docker builder prune -af >>"$LOG_FILE" 2>&1 || true docker image prune -af >>"$LOG_FILE" 2>&1 || true docker container prune -f >>"$LOG_FILE" 2>&1 || true else docker builder prune -af --filter "until=72h" --max-used-space=4g >>"$LOG_FILE" 2>&1 || true docker image prune -af --filter "until=168h" >>"$LOG_FILE" 2>&1 || true docker container prune -f --filter "until=24h" >>"$LOG_FILE" 2>&1 || true fi printf '\n[%s] === docker prune complete%s ===\n' "$(now)" "$( (( FORCE )) && printf ' (FORCE)' )" >>"$LOG_FILE" docker system df >>"$LOG_FILE" 2>&1 || true