11#! /usr/bin/env bash
2+ set -euo pipefail
3+
4+ # ================================
5+ # Docker Swarm Cluster Cleanup Script
6+ # ================================
7+ # Features:
8+ # --dry-run Preview cleanup (default if no flag is provided)
9+ # --live Actually prune images
10+ # --dangling-only Remove ONLY dangling (<none>) images
11+ # --all Remove ALL unused images (default for live)
12+ # --confirm CLEAN Skip interactive confirmation (cron-friendly)
13+ #
14+ # Usage examples:
15+ # ./cleanup_unused_images.sh --dry-run
16+ # ./cleanup_unused_images.sh --live --dangling-only
17+ # ./cleanup_unused_images.sh --live --all --confirm CLEAN
18+ # =================================
219
320# List of all your Swarm nodes
421NODES=(
@@ -10,38 +27,86 @@ NODES=(
1027 " docker-prod-worker3"
1128)
1229
30+ MODE=" dry-run"
31+ PRUNE_TYPE=" all"
32+ CONFIRM_INPUT=" "
33+
34+ # ===== Parse Flags =====
35+ while [[ $# -gt 0 ]]; do
36+ case " $1 " in
37+ --dry-run) MODE=" dry-run" ;;
38+ --live) MODE=" live" ;;
39+ --dangling-only) PRUNE_TYPE=" dangling" ;;
40+ --all) PRUNE_TYPE=" all" ;;
41+ --confirm) CONFIRM_INPUT=" ${2:- } " ; shift ;;
42+ * ) echo " ❌ Unknown option: $1 " ; exit 1 ;;
43+ esac
44+ shift
45+ done
46+
47+ LOGFILE=" ./docker_cleanup_$( date +%F) .log"
48+ exec > >( tee -a " $LOGFILE " ) 2>&1
49+
1350echo " === Docker Swarm Cluster Cleanup ==="
14- echo " This script will connect to each node and prune unused images."
51+ echo " Mode: $MODE "
52+ echo " Prune type: $PRUNE_TYPE "
53+ echo " Nodes: ${# NODES[@]} "
54+ echo " Logs: $LOGFILE "
1555echo " -------------------------------------"
1656
17- # First, show disk usage before cleanup
57+ # Pick correct prune command
58+ if [[ " $PRUNE_TYPE " == " dangling" ]]; then
59+ PRUNE_CMD=" sudo docker image prune -f"
60+ else
61+ PRUNE_CMD=" sudo docker image prune -a -f"
62+ fi
63+
64+ # Step 1: Show disk usage before cleanup
1865for NODE in " ${NODES[@]} " ; do
1966 echo " ---- $NODE : Disk usage before ----"
20- ssh serveradmin@$NODE " sudo docker system df"
67+ ssh -o BatchMode=yes serveradmin@" $NODE " " sudo docker system df || true "
2168done
2269
23- # Then show which images will be removed (manual preview since there's no --dry-run)
70+ # Step 2: Preview images that *would* be removed
71+ echo " ---- DRY-RUN PREVIEW ----"
2472for NODE in " ${NODES[@]} " ; do
25- echo " ---- $NODE : Dangling images preview ----"
26- ssh serveradmin@$NODE " sudo docker images -f 'dangling=true'"
73+ echo " Node: $NODE "
74+ ssh -o BatchMode=yes serveradmin@" $NODE " "
75+ echo 'Dangling Images:' &&
76+ sudo docker images -f 'dangling=true' --format '{{.Repository}}:{{.Tag}} {{.ID}} {{.Size}}' || true
77+ echo '---'
78+ if [[ \" $PRUNE_TYPE \" == \" all\" ]]; then
79+ echo 'Unused Tagged Images:' &&
80+ sudo docker images --filter 'dangling=false' --format '{{.Repository}}:{{.Tag}} {{.ID}} {{.Size}}' |
81+ grep -v '<none>' || echo 'None'
82+ else
83+ echo '(Skipping unused tagged images: dangling-only mode)'
84+ fi
85+ "
2786done
2887
29- read -rp " Proceed to prune unused images on all nodes? (y/N): " CONFIRM
30- if [[ " $CONFIRM " != " y" && " $CONFIRM " != " Y" ]]; then
31- echo " Aborted."
32- exit 1
88+ # If dry-run, exit safely
89+ if [[ " $MODE " == " dry-run" ]]; then
90+ echo " ✅ Dry-run complete. No images were deleted."
91+ exit 0
92+ fi
93+
94+ # Step 3: If live mode, require confirmation
95+ if [[ " $CONFIRM_INPUT " != " CLEAN" ]]; then
96+ read -rp " ⚠️ Type CLEAN to prune images across ALL nodes: " CONFIRM_INPUT
97+ [[ " $CONFIRM_INPUT " != " CLEAN" ]] && echo " Aborted." && exit 1
3398fi
3499
35- # Run actual prune
100+ # Step 4: Run prune command on all nodes
36101for NODE in " ${NODES[@]} " ; do
37- echo " ---- $NODE : Pruning unused images ----"
38- ssh serveradmin@$NODE " sudo docker image prune -a -f "
102+ echo " ---- $NODE : Pruning images ----"
103+ ssh -o BatchMode=yes serveradmin@" $NODE " " $PRUNE_CMD || true "
39104done
40105
41- # Show disk usage after cleanup
106+ # Step 5: Show disk usage after cleanup
42107for NODE in " ${NODES[@]} " ; do
43108 echo " ---- $NODE : Disk usage after ----"
44- ssh serveradmin@$NODE " sudo docker system df"
109+ ssh -o BatchMode=yes serveradmin@" $NODE " " sudo docker system df || true "
45110done
46111
47- echo " ✅ Done! All unused images have been cleaned up across the cluster. "
112+ echo " ✅ Done! Cleanup complete. Logs saved to $LOGFILE "
0 commit comments