占用

执行 df -h 和 du -h --max-depth=1 汇总后得到资源主要由以下内容占用:

1.devicemapper
2.logs
3.容器内日志
4.无用的 volumes

解决措施

针对 devicemapper

针对 容器日志

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash

for container_id in $(docker ps -a --filter="name=$name" -q);

do file=$(docker inspect $container_id | grep -G '"LogPath": "*"' | sed -e 's/.*"LogPath": "//g' | sed -e 's/",//g');

if [ -f $file ]
then
echo $file;
fi

done

针对 容器内日志

无用的 volumes

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
134
135
136
137
138
139
140
141
142
143
144
#! /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/--graph option
dockerpid=$(ps ax | grep "$docker_bin" | grep -v grep | awk '{print $1; exit}') || :
if [[ -n "$dockerpid" && $dockerpid -gt 0 ]]; then
next_arg_is_dockerdir=false
while read -d $'\0' arg
do
if [[ $arg =~ ^--graph=(.+) ]]; then
dockerdir=${BASH_REMATCH[1]}
break
elif [ $arg = '-g' ]; then
next_arg_is_dockerdir=true
elif [ $next_arg_is_dockerdir = true ]; then
dockerdir=$arg
break
fi
done < /proc/$dockerpid/cmdline
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() {
local 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"
local dir
while read -d $'\0' dir
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 < <(find "${targetdir}" -mindepth 1 -maxdepth 1 -type d -print0 2>/dev/null)
}

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
log_verbose "Inspecting container ${container}"
for volpath in $(
${docker_bin} inspect --format='{{range $key, $val := .}}{{if eq $key "Volumes"}}{{range $vol, $path := .}}{{$path}}{{"\n"}}{{end}}{{end}}{{if eq $key "Mounts"}}{{range $mount := $val}}{{$mount.Source}}{{"\n"}}{{end}}{{end}}{{end}}' ${container} \
); do
log_verbose "Processing volumepath ${volpath}"
#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}"