Last active
February 4, 2025 06:33
-
-
Save seanslma/05c2176e18b8f33b34a1af8f059b4562 to your computer and use it in GitHub Desktop.
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/bash | |
# This script removes tags from local registry, keeping just the n most recents tags | |
# after this script run, run the following script to free the space: | |
# bin/registry garbage-collect /etc/docker/registry/config.yml | |
# | |
# Examples (dryrun and execution): | |
# ./delete_registry_digests.sh -r http://registry.local:5000 -i test -k 0 | |
# ./delete_registry_digests.sh -r https://registry.example.com -i dev/test -e latest -d | |
# | |
# After deleting all the tags, run garbage collection: | |
# registry garbage-collect -m /etc/docker/registry/config.yml | |
# | |
# based on: https://gist.github.com/jaytaylor/86d5efaddda926a25fa68c263830dac1?permalink_comment_id=4732942#gistcomment-4732942 | |
# and on: https://stackoverflow.com/questions/31251356/how-to-get-a-list-of-images-on-docker-registry-v2 | |
# Abels changes: | |
# - Not using jq utility, just curl and native linux binaries | |
# - Check based tag count, removing last n versions | |
# Sean's changes: | |
# - Add timestamp option - only delete tags earlier than the timestamp | |
# - Add delete option - default to dryrun | |
# - Add help option | |
# Function to check if has more than n tags and remove | |
check_tags_more_than_n_versions() { | |
# Get tag list, not sorted | |
local tagurl="${registry}/v2/${image}/tags/list" | |
echo "Registry : ${registry}" | |
echo "Image name: ${image}" | |
echo | |
local tags=$(curl -k -s -u $user:$password "$tagurl" | awk -F: '{print $3}' | sed -e 's/[][]//g' -e 's/\"//g' -e 's/ //g' -e 's/,/\n/g' | tr '}' '\n' | tr '{' '\n') | |
# Filter tags that has this string (optional) | |
if [ -n "$only" ]; then | |
tags=$(echo "${tags}" | grep "$only") | |
fi | |
# Exclude tags that has this string (optional) | |
if [ -n "$exclude" ]; then | |
tags=$(echo "${tags}" | grep -v "$exclude") | |
fi | |
local tagsWithTS="" | |
local keepTS=0 | |
if [ -n "$tags" ]; then | |
# timestamp | |
if [ -n "$timestampMin" ]; then | |
local timestamp_min=$(date -d "$timestampMin" +%s) | |
fi | |
# Get created timestamp for each tag | |
for tag in $tags; do | |
local created_time=$(curl -k -s -u $user:$password -H 'Accept: application/vnd.docker.distribution.manifest.v1+json' -X GET $registry/v2/$image/manifests/$tag | grep -i v1Compatibility | head -n1 | awk -F'created' '{print $2}' | awk -F'"' '{print $3}' | sed -e 's/\\//g') | |
created_time=$(echo $created_time | sed -e 's/T/ /g' | awk -F'.' '{print $1}') | |
local created_timestamp=$(date -d "$created_time" +%s) | |
if [ -n "$timestampMin" ]; then | |
if [ "$created_timestamp" -lt "$timestamp_min" ]; then | |
tagsWithTS="${tagsWithTS}${created_timestamp}|${tag} " | |
else | |
((keepTS++)) | |
fi | |
else | |
tagsWithTS="${tagsWithTS}${created_timestamp}|${tag} " | |
fi | |
done | |
#Sort tags by time stamp and remove from list keeplast values, keeping tags to remove | |
if [ "$keepTS" -gt "$keeplast" ]; then | |
keeplast=0 | |
else | |
keeplast=$((keeplast - keepTS)) | |
fi | |
tagsWithTS=$(echo $tagsWithTS | xargs -n1 | sort -r -n -t'|' -k1) | |
tagsWithTS=$(echo $tagsWithTS | xargs -n1 | sed -n $((keeplast + 1)),1000p) | |
# Tags to remove | |
local lasttagdigest="" | |
if [ -n "$tagsWithTS" ]; then | |
echo "The following image digests will be deleted:" | |
for tagWithTS in $tagsWithTS; do | |
timestamp=$(echo "$tagWithTS" | awk -F'|' '{print $1}') | |
formatted_timestamp=$(date -d "@$timestamp" +%Y-%m-%d\ %H:%M:%S) | |
tag=$(echo "$tagWithTS" | awk -F'|' '{print $2}') | |
local tagdigest=$(curl -s -k -I -u "$user:$password" -H "Accept: application/vnd.docker.distribution.manifest.v2+json" "${registry}/v2/${image}/manifests/${tag}" | grep -i 'docker-content-digest: ' | awk -F': ' '{print $2}' | sed 's/[\r\n]//g') | |
local url="${registry}/v2/${image}/manifests/${tagdigest}" | |
if [ "$delete" = true ]; then | |
if [ "$tagdigest" != "$lasttagdigest" ]; then | |
curl -s -k -u "$user:$password" -X DELETE $url | |
fi | |
echo " Deleted tag: ${formatted_timestamp} - ${image}:${tag}" | |
else | |
echo " ${formatted_timestamp} - ${image}:${tag}" | |
fi | |
done | |
else | |
echo "No image digests to be deleted" | |
fi | |
else | |
echo "No tags found for image: ${image}" | |
fi | |
} | |
HELPMSG=" | |
Basic usage | |
$0 -r {registry_url} -i {image-name} | |
Options avaliable | |
-h help on how to use the command | |
-r (required) registry url | |
-i (required) image name | |
-k keep last n (default 10) | |
-t keep tags with timestamp >= t | |
-o keep only tags that contains this string | |
-e exclude tags if name contains this string | |
-u user | |
-p password | |
-d delete the manifests, otherwise dryrun to only show info | |
Examples | |
$0 -r http://registry.local:5000 -i test -k 0 | |
$0 -r https://registry.example.com -i dev/test -e latest -d | |
" | |
# Initialize variables | |
registry="" | |
image="" | |
keeplast="" | |
timestampMin="" | |
only="" | |
exclude="" | |
user="" | |
password="" | |
delete=false | |
while getopts "hr:i:k:t:o:e:u:p:d" opt; do | |
case "$opt" in | |
h) echo "$HELPMSG"; exit 0 ;; | |
r) registry="$OPTARG" ;; | |
i) image="$OPTARG" ;; | |
k) keeplast="$OPTARG" ;; | |
t) timestampMin="$OPTARG" ;; | |
o) only="$OPTARG" ;; | |
e) exclude="$OPTARG" ;; | |
u) user="$OPTARG" ;; | |
p) password="$OPTARG" ;; | |
d) delete=true ;; | |
\?) echo "Invalid option: -$OPTARG" >&2; exit 1 ;; | |
esac | |
done | |
# Set keeplast default value to 10 | |
if [ -z "$keeplast" ]; then keeplast=5; fi | |
# Required params | |
if [ -z "$registry" ]; then echo "Error: Registry (-r) required"; echo "$HELPMSG"; exit 1; fi | |
if [ -z "$image" ]; then echo "Error: Image (-i) required"; echo "$HELPMSG"; exit 1; fi | |
check_tags_more_than_n_versions |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment