forked from meltwater/docker-cleanup
-
Notifications
You must be signed in to change notification settings - Fork 1
/
docker-cleanup-volumes.sh
executable file
·133 lines (116 loc) · 4.59 KB
/
docker-cleanup-volumes.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#! /bin/bash
set -eou pipefail
#usage: sudo ./docker-cleanup-volumes.sh [--dry-run]
docker_bin=$(which docker.io 2> /dev/null || which docker 2> /dev/null)
# Default dir
dockerdir=/var/lib/docker
# Look for an alternate docker directory with -g option
dockerPs=`ps aux | grep $docker_bin | grep -v grep` || :
if [[ $dockerPs =~ ' -g ' ]]; then
dockerdir=`echo $dockerPs | sed 's/.* -g//' | cut -d ' ' -f 2`
elif [[ $dockerPs =~ ' --graph=' ]]; then
dockerdir=`echo $dockerPs | sed 's/.* --graph//' | cut -d '=' -f 2 | awk '{print $1}'`
fi
dockerdir=$(readlink -f $dockerdir)
volumesdir=${dockerdir}/volumes
vfsdir=${dockerdir}/vfs/dir
allvolumes=()
dryrun=false
verbose=false
function log_verbose() {
if [ "${verbose}" = true ]; then
echo "$1"
fi;
}
function delete_volumes() {
targetdir=$1
echo
if [[ ! -d ${targetdir} || ! "$(ls -A ${targetdir})" ]]; then
echo "Directory ${targetdir} does not exist or is empty, skipping."
return
fi
echo "Delete unused volume directories from $targetdir"
for dir in $(find ${targetdir} -mindepth 1 -maxdepth 1 -type d 2>/dev/null)
do
dir=$(basename $dir)
if [[ -d "${targetdir}/${dir}/_data" || "${dir}" =~ [0-9a-f]{64} ]]; then
if [ ${#allvolumes[@]} -gt 0 ] && [[ ${allvolumes[@]} =~ "${dir}" ]]; then
echo "In use ${dir}"
else
if [ "${dryrun}" = false ]; then
echo "Deleting ${dir}"
rm -rf "${targetdir}/${dir}"
else
echo "Would have deleted ${dir}"
fi
fi
else
echo "Not a volume ${dir}"
fi
done
}
if [ $UID != 0 ]; then
echo "You need to be root to use this script."
exit 1
fi
if [ -z "$docker_bin" ] ; then
echo "Please install docker. You can install docker by running \"wget -qO- https://get.docker.io/ | sh\"."
exit 1
fi
while [[ $# > 0 ]]
do
key="$1"
case $key in
-n|--dry-run)
dryrun=true
;;
-v|--verbose)
verbose=true
;;
*)
echo "Cleanup docker volumes: remove unused volumes."
echo "Usage: ${0##*/} [--dry-run] [--verbose]"
echo " -n, --dry-run: dry run: display what would get removed."
echo " -v, --verbose: verbose output."
exit 1
;;
esac
shift
done
# Make sure that we can talk to docker daemon. If we cannot, we fail here.
${docker_bin} version >/dev/null
container_ids=$(${docker_bin} ps -a -q --no-trunc)
#All volumes from all containers
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
for container in $container_ids; do
#add container id to list of volumes, don't think these
#ever exists in the volumesdir but just to be safe
allvolumes+=${container}
#add all volumes from this container to the list of volumes
for volpath in $(
${docker_bin} inspect --format='{{range $vol, $path := .Volumes}}{{$path}}{{"\n"}}{{end}}' ${container}; \
${docker_bin} inspect --format='{{range $mount := .Mounts}}{{$mount.Source}}{{"\n"}}{{end}}' ${container} \
); do
log_verbose "Processing volumepath ${volpath} for container ${container}"
#try to get volume id from the volume path
vid=$(echo "${volpath}"|sed 's|.*/\(.*\)/_data$|\1|;s|.*/\([0-9a-f]\{64\}\)$|\1|')
# check for either a 64 character vid or then end of a volumepath containing _data:
if [[ "${vid}" =~ ^[0-9a-f]{64}$ || (${volpath} =~ .*/_data$ && ! "${vid}" =~ "/") ]]; then
log_verbose "Found volume ${vid}"
allvolumes+=("${vid}")
else
#check if it's a bindmount, these have a config.json file in the ${volumesdir} but no files in ${vfsdir} (docker 1.6.2 and below)
for bmv in $(find ${volumesdir} -name config.json -print | xargs grep -l "\"IsBindMount\":true" | xargs grep -l "\"Path\":\"${volpath}\""); do
bmv="$(basename "$(dirname "${bmv}")")"
log_verbose "Found bindmount ${bmv}"
allvolumes+=("${bmv}")
#there should be only one config for the bindmount, delete any duplicate for the same bindmount.
break
done
fi
done
done
IFS=$SAVEIFS
delete_volumes ${volumesdir}
delete_volumes ${vfsdir}