Last active
November 30, 2023 21:18
-
-
Save agners/c5ae781c828dbf76c4cc1e4588c034a5 to your computer and use it in GitHub Desktop.
Prune corrupted Docker layers in overlayfs2 storage
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
# (c) 2023 Stefan Agner | |
# This scripts attempts to clear corrupted Docker overlay2 storage metadata | |
# which can be left over after a power failure. | |
# See also: https://github.com/moby/moby/issues/42964 | |
# | |
# Typically the error message when attempting to pull the image for which | |
# corrupted layers are in the storage looks like: | |
# failed to register layer: error creating overlay mount to /mnt/data/docker/overlay2/6ee02298ee75a4f96e77f90551673cb700f29867f9ad1c4e20b8c816bfcf0735/merged: too many levels of symbolic links | |
# Docker storage directory, intended for Home Assistant OS | |
docker_storage_dir="/mnt/data/docker" | |
# Warning message | |
echo "WARNING: This script attempts to clear corrupted Docker overlay2 storage metadata." | |
echo "Use with caution, as it may result in data loss. Ensure you have backups before running this script." | |
# Initial sanity check for the overlay2 directory | |
overlay2_dir="$docker_storage_dir/overlay2" | |
layerdb_dir="$docker_storage_dir/image/overlay2/layerdb/sha256" | |
if [ ! -d "$overlay2_dir" ]; then | |
echo "Error: Directory $overlay2_dir does not exist." | |
exit 1 | |
fi | |
# Find unique cache IDs | |
cache_ids=$(find "$overlay2_dir" -type f -size 0 \( -name lower -o -name link \) -exec sh -c 'basename $(dirname {})' \; | sort -u) | |
# Check if cache IDs are found | |
if [ -z "$cache_ids" ]; then | |
echo "No cache IDs with size 0 found. Exiting." | |
exit 0 | |
fi | |
# Count the number of cache IDs found | |
num_cache_ids=$(echo "$cache_ids" | wc -w) | |
# Prompt the user for confirmation | |
echo "Found $num_cache_ids cache IDs with size 0. Do you want to continue and delete them? (yes/no)" | |
read user_confirmation | |
# Check user's response | |
if [ "$user_confirmation" != "yes" ]; then | |
echo "Operation canceled. No directories were deleted." | |
exit 0 | |
fi | |
# Initialize counters for summary | |
deleted_cache_dirs=0 | |
deleted_layerdb_dirs=0 | |
# Iterate through cache IDs | |
for cache_id in $cache_ids; do | |
# Find corresponding directory in layerdb | |
layerdb_dir_path=$(dirname $(grep -r -e "$cache_id" "$layerdb_dir"/*/cache-id)) | |
cache_dir="$overlay2_dir/$cache_id" | |
# Remove cache directory | |
if [ -d "$cache_dir" ]; then | |
rm -rf "$cache_dir" | |
deleted_cache_dirs=$((deleted_cache_dirs + 1)) | |
fi | |
# Remove LayerDB directory | |
if [ -d "$layerdb_dir_path" ]; then | |
rm -rf "$layerdb_dir_path" | |
deleted_layerdb_dirs=$((deleted_layerdb_dirs + 1)) | |
fi | |
done | |
# Print summary | |
echo "Summary: Deleted $deleted_cache_dirs cache directories and $deleted_layerdb_dirs LayerDB directories." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment