#!/bin/bash # ============================================================================================== # ============================= Docker Prune Images ============================================ # ============================================================================================== # # PURPOSE # ───────────────────────────────────────────────────────────────────────────── # Removes dangling Docker images — images no longer tagged or referenced by any # container. These accumulate after container updates pull a new image version, # leaving the old image behind with no tag. # # Safe to run at any time. Only removes images with no tag and no container # reference — running containers are never affected. # # ============================================================================================== # RUNTIME MODES # ============================================================================================== # # docker_prune_images.sh # Show dangling images and remove them. # # docker_prune_images.sh --dry-run # Show what would be removed without removing anything. # # docker_prune_images.sh --status # Show current dangling images and disk usage. No changes. # # ============================================================================================== SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/../load_config.sh" parse_args "$@" # ============================================================================================== # ━━━ Setup ━━━ # ============================================================================================== if [[ "$EUID" -ne 0 ]]; then error "Must be run as root" exit 1 fi acquire_lock # ============================================================================================== # ━━━ Status ━━━ # ============================================================================================== if [[ "$SHOW_STATUS" == true ]]; then echo "" echo "━━━━━ $ICON_SUMMARY DOCKER PRUNE IMAGES STATUS ━━━━━" DANGLING=$(docker images -f "dangling=true" --format "{{.ID}}\t{{.Size}}\t{{.CreatedSince}}" 2>/dev/null) if [[ -z "$DANGLING" ]]; then echo "$ICON_DONE No dangling images." else COUNT=$(echo "$DANGLING" | wc -l) echo "$ICON_CONTAINERS $COUNT dangling image(s):" echo "$DANGLING" | while IFS=$'\t' read -r id size age; do echo " $id $size created $age" done fi echo "━━━━━━━━━━━━━━━━━━━━━━━" exit 0 fi # ============================================================================================== # ━━━ Run ━━━ # ============================================================================================== echo "━━━ $ICON_CONTAINERS Docker Prune Images — $(date '+%Y-%m-%d %H:%M:%S') ━━━" DANGLING_IDS=$(docker images -f "dangling=true" -q 2>/dev/null) if [[ -z "$DANGLING_IDS" ]]; then success "No dangling images — nothing to do" exit 0 fi COUNT=$(echo "$DANGLING_IDS" | wc -l) log "Found $COUNT dangling image(s)" if [[ "$DRY_RUN" == true ]]; then warn "DRY RUN — would remove $COUNT dangling image(s):" docker images -f "dangling=true" --format " {{.ID}} {{.Size}} created {{.CreatedSince}}" 2>/dev/null exit 0 fi OUTPUT=$(docker image prune -f 2>&1) echo "$OUTPUT" RECLAIMED=$(echo "$OUTPUT" | grep -E "^Total reclaimed" || echo "") if [[ -n "$RECLAIMED" ]]; then success "Done — $RECLAIMED" else success "Done — $COUNT image(s) removed" fi