Skip to content

Instantly share code, notes, and snippets.

@jaytaylor
Last active June 10, 2024 13:57
Show Gist options
  • Save jaytaylor/86d5efaddda926a25fa68c263830dac1 to your computer and use it in GitHub Desktop.
Save jaytaylor/86d5efaddda926a25fa68c263830dac1 to your computer and use it in GitHub Desktop.
One liner for deleting images from a v2 docker registry

One liner for deleting images from a v2 docker registry

Just plug in your own values for registry and repo/image name.

registry='localhost:5000'
name='my-image'
curl -v -sSL -X DELETE "http://${registry}/v2/${name}/manifests/$(
    curl -sSL -I \
        -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
        "http://${registry}/v2/${name}/manifests/$(
            curl -sSL "http://${registry}/v2/${name}/tags/list" | jq -r '.tags[0]'
        )" \
    | awk '$1 == "Docker-Content-Digest:" { print $2 }' \
    | tr -d $'\r' \
)"

If all goes well

* About to connect() to localhost port 5000 (#0)
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 5000 (#0)
> DELETE /v2/my-image/manifests/sha256:14f6ecba1981e49eb4552d1a29881bc315d5160c6547fdd100948a9e30a90dff HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:5000
> Accept: */*
>
< HTTP/1.1 202 Accepted
< Docker-Distribution-Api-Version: registry/2.0
< X-Content-Type-Options: nosniff
< Date: Wed, 15 Nov 2017 23:25:30 GMT
< Content-Length: 0
< Content-Type: text/plain; charset=utf-8
<
* Connection #0 to host localhost left intact

Garbage cleanup

Finally, invoke garbage cleanup on the docker-registry container.

For example:

docker exec -it docker-registry bin/registry garbage-collect /etc/docker/registry/config.yml
@lautitoti
Copy link

@DKroot Looks good, thanks!

Is it not an idea to select on max age or how many tags/versions of an image ?

I needed the same @di-rect , so I hope it helps you (or someone else) too :)

#!/bin/bash

# based on: https://gist.github.com/jaytaylor/86d5efaddda926a25fa68c263830dac1
# changes: 
# - Check for images older than a year 
-----------
# Function to check tags older than a year
check_tags_older_than_a_year() {
    local registry=$1
    local image=$2
    local user=$3
    local password=$4

    local tags=$(curl -s -u "$user:$password" "https://${registry}/v2/${image}/tags/list" | jq -r '.tags // [] | .[]')

    if [[ -n $tags ]]; then
        for tag in $tags; do
            # For manifests v2 uncomment the following line and comment the v1 version.
            # local created_time=$(curl -s -I -u "$user:$password" -H "Accept: application/vnd.docker.distribution.manifest.v2+json" "https://${registry}/v2/${image}/manifests/${tag}" | jq -r '[.history[]]|map(.v1Compatibility|fromjson|.created)|sort|reverse|.[0]')
            local created_time=$(curl -s -u $user:$password -H 'Accept: application/vnd.docker.distribution.manifest.v1+json' -X GET https://$registry/v2/$image/manifests/$tag | jq -r '[.history[]]|map(.v1Compatibility|fromjson|.created)|sort|reverse|.[0]')
            local created_timestamp=$(date -d "$created_time" +%s)
            local current_timestamp=$(date +%s)
            local age_days=$(( (current_timestamp - created_timestamp) / (60*60*24) ))

            if [[ $age_days -gt 365 ]]; then
                echo "Tag $tag of image $image is older than a year. Deleting..."
                # Uncomment the following line to actually delete the tag
                curl -s -u "$user:$password" -X DELETE "https://${registry}/v2/${image}/manifests/$(curl -s -I -u "$user:$password" -H "Accept: application/vnd.docker.distribution.manifest.v2+json" "https://${registry}/v2/${image}/manifests/${tag}" | grep -i 'docker-content-digest' | awk -F': ' '{print $2}' | sed 's/[\r\n]//g')"
            fi
        done
    else
        echo "No tags found for image $image."
    fi
}

# Main function
main() {
    echo "Specify private image registry url without https://"
    read -r registry

    echo "List images, separated by space"
    read -r images

    echo "Registry User:"
    read -r user

    echo "Registry Password:"
    read -s password

    IFS=' ' read -r -a images_array <<< "$images"
    for image in "${images_array[@]}"; do
        echo "Checking tags for image $image..."
        check_tags_older_than_a_year "$registry" "$image" "$user" "$password"
    done
}

# Run the main function
main

@ehdis
Copy link

ehdis commented Mar 1, 2024

One liner :-)
skopeo delete docker://localhost:5000/apps/registry:latest

@abelmferreira
Copy link

hi everybody
i need something similar @lautitoti created, but not based on time, based on registry image tag count

I publish the script here
https://gist.github.com/abelmferreira/c38036f9642f2adf260ad068ac08f187

@seanslma
Copy link

I updated the solution from @abelmferreira

  • added -h option: show help info
  • added -t option: min timestamp to keep
  • added -d flag: delete or dry run

The updated script:
https://gist.github.com/seanslma/05c2176e18b8f33b34a1af8f059b4562

@vnovichek
Copy link

https://github.com/fraunhoferfokus/deckschrubber
written in go so quite fast, supports all options of choosing images plus it fetches repositories from the registry

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