Skip to content

Instantly share code, notes, and snippets.

@chuanqi129
Forked from fayak/docker-pruner.sh
Last active May 29, 2025 03:11
Show Gist options
  • Save chuanqi129/8eb285634d330a09168883b9abbbe698 to your computer and use it in GitHub Desktop.
Save chuanqi129/8eb285634d330a09168883b9abbbe698 to your computer and use it in GitHub Desktop.
Docker pruner. Deletes docker's overlay2 leftovers that survive 'docker system prune -af --volumes'
#!/usr/bin/env bash
set -eEuo pipefail
MARKER_FILE_NAME="${DOCKER_PRUNER_MARKER:-DOCKER-PRUNER-MARKER-FILE}"
DOCKER_PATH="${DOCKER_PATH:-/var/lib/docker/overlay2}"
function _used_dirs() {
for docker_obj in $(docker ps -aq) $(docker image ls -aq); do
lowerdir="$(docker inspect "$docker_obj" | jq '.[].GraphDriver.Data.LowerDir' -r)"
for dir in ${lowerdir//:/ }; do
dirname "$dir"
done
dirname "$(docker inspect "$docker_obj" | jq '.[].GraphDriver.Data.MergedDir' -r)"
done
}
function used_dirs() {
_used_dirs | sort
}
function all_dirs() {
find "$DOCKER_PATH"/ -maxdepth 1 -type d | grep -Ev '^'"$DOCKER_PATH"'/?l?$' | sort
}
function unused_dirs() {
all_dirs_tmp=$(all_dirs)
used_dirs_tmp=$(used_dirs)
grep -v -xF -f <(echo ${used_dirs_tmp} | tr " " "\n") <(echo ${all_dirs_tmp} | tr " " "\n")
}
function set_marker() {
touch "$1"/merged/"$MARKER_FILE_NAME" 2> /dev/null || \
touch "$1"/diff/"$MARKER_FILE_NAME"
}
function _check() {
for container in $(docker ps -aq); do
docker exec "$container" ls "/$MARKER_FILE_NAME" && echo "container: $container" || true
done
for image in $(docker image ls -aq); do
docker run --rm -it --entrypoint ls "$image" "/$MARKER_FILE_NAME" && echo "image: $image" || true
done
}
function check() {
output="$(_check 2>&1 | grep -Ev /"$MARKER_FILE_NAME'?"': No such file or directory')"
if [[ -n "$output" ]]; then
echo "Problem detected !"
echo "$output"
exit 1
fi
}
function usage() {
echo -e "Usage:
\t$0 list -- List all directories that needs to be removed
\t$0 marker -- Put a marker on each directory, to check if the marker in found in a running container (detecting an issue with $0)
\t$0 check -- Check if a marker is found. Must have run $0 marker first to make sense
\t$0 clear -- Remove the directories"
}
if [[ $# == 0 ]]; then
usage ; exit 0
fi
if [ "$EUID" -ne 0 ]
then echo "Please run as root"
exit 1
fi
if [[ "$1" == "list" ]]; then
unused_dirs 2>&1 | tee .unused_dir.log
cat .unused_dir.log | xargs -I {} sh -c 'cat {}"/link"; echo \n' | xargs -I {} echo "${DOCKER_PATH}/l/"{} 2>&1 | tee .unused_dir_link.log
elif [[ "$1" == "marker" ]]; then
export -f set_marker
export MARKER_FILE_NAME="$MARKER_FILE_NAME"
cat .unused_dir.log | xargs -I {} bash -c "set_marker {}"
elif [[ "$1" == "check" ]]; then
check
elif [[ "$1" == "clear" ]]; then
cat .unused_dir.log | xargs -I {} find {} -delete
cat .unused_dir_link.log | xargs -I {} rm -rf {}
elif [[ "$1" == "fn" ]]; then
$2 "$@"
fi
@chuanqi129
Copy link
Author

$ cat docker-pruner-timer.sh 
echo "=============================Docker prune start============================="
date
df -h
docker images
docker ps -a
nbuild=$(ps -ef | grep -c -e "docker build" -e "docker pull")
if [[ $nbuild -eq 1 ]]; then
    sudo /home/sdp/docker-pruner.sh list
    sudo /home/sdp/docker-pruner.sh marker 
    sudo /home/sdp/docker-pruner.sh check 
    sudo /home/sdp/docker-pruner.sh clear 
    docker system  prune -af
else
    echo "Docker image building/pulling ...."
fi
df -h
docker images
docker ps -a

Then use crontab to setup a task
0 */4 * * * bash /home/sdp/docker-pruner-timer.sh 2>&1 | tee -a /home/sdp/docker_pruner.log

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment