Listing the tags of a Docker image on a Docker hub through the HTTP API
Asked Answered
D

6

7

I would like to list the tags of a Docker image official Docker hub through its HTTP interface, but I am a bit confused. As there seems to two versions of them:

I managed to get them through sending a GET request to this endpoint: https://index.docker.io/v1/repositories/{my-namespace}/{my-repository}/tags along with basic authentication credentials.

I am not sure if there is a correct one among them, but which should I be using?

Dittmer answered 12/2, 2016 at 11:8 Comment(0)
G
2

Docker made a huge refactor of the registry: registry v2.0.

With this brand new version, comes a new authentication system so the basic auth of v1.0 will not work anymore.

You can find more details about the v2.0 auth here: https://docs.docker.com/v1.6/registry/spec/auth/token/

As v1.0 is deprecated, you should move forward to registry v2.0.

Grimmett answered 12/2, 2016 at 16:31 Comment(0)
T
5

I'm arriving a little late, I searched this question as list all tags for the same image (understand digest), unfortunately most of the answers are only about displaying all available tags for any image digest that was pushed.

Case in hand, for open jdk the same image digest is usually tagged multiple times :

  {
    "sha256:518f6c2137b7463272cb1f52488e914b913b92bfe0783acb821c216987959971": [
      "11",
      "11-buster",
      "11-jdk",
      "11-jdk-buster",
      "11.0",
      "11.0-buster",
      "11.0-jdk",
      "11.0-jdk-buster",
      "11.0.8",
      "11.0.8-buster",
      "11.0.8-jdk",
      "11.0.8-jdk-buster"
    ]
  },

I wasn't able to find the relevant API v2, it seems the api exposes tags, but there's no details and otherwise you need to list each blob manifest to get matching digest via the response header Docker-Content-Digest. I Unless I missed something this unusable for my use case when there is a lot of tags, so I just used the regular dockerhub API to get all tags and teir details and group these tags by the image digest.

(
  url="https://registry.hub.docker.com/v2/repositories/library/openjdk/tags/?page_size=100" ;
  while [ -n "$url" ]; do
    >&2 echo -n ".";
    content="$(curl -s "$url")";
    url=$(jq -r '.next // empty' <<< "${content}");
    echo "$content";
  done;
  >&2 echo;
) | jq -s '[.[].results[]]' \
  | jq 'map({tag: .name, digest: .images[].digest}) | unique | group_by(.digest) | map(select(.[].digest) | {(.[0].digest): [.[].tag]})' \
  > openjdk-tags.json

I've published this as a script in this gist, any comment or suggestion would be appreciated.

Treece answered 16/10, 2020 at 9:58 Comment(1)
Just wanted to send a thank you for the script, it's great!Dieter
B
4

Update for Docker V2 API

The Docker V2 API requires an OAuth bearer token with the appropriate claims. In my opinion, the official documentation is rather vague on the topic. So that others don't go through the same pain I did, I offer the below docker-tags function.

The most recent version of docker-tags can be found in my GitHubGist : "List Docker Image Tags using bash".

The docker-tags function has a dependency on jq. If you're playing with JSON, you likely already have it.

#!/usr/bin/env bash
docker-tags() {
    arr=("$@")

    for item in "${arr[@]}";
    do
        tokenUri="https://auth.docker.io/token"
        data=("service=registry.docker.io" "scope=repository:$item:pull")
        token="$(curl --silent --get --data-urlencode ${data[0]} --data-urlencode ${data[1]} $tokenUri | jq --raw-output '.token')"
        listUri="https://registry-1.docker.io/v2/$item/tags/list"
        authz="Authorization: Bearer $token"
        result="$(curl --silent --get -H "Accept: application/json" -H "Authorization: Bearer $token" $listUri | jq --raw-output '.')"
        echo $result
    done
}

Example

docker-tags "microsoft/nanoserver" "microsoft/dotnet" "library/mongo" "library/redis"

Admittedly, docker-tags makes several assumptions. Specifically, the OAuth request parameters are mostly hard coded. A more ambitious implementation would make an unauthenticated request to the registry and derive the OAuth parameters from the unauthenticated response.

Butyrate answered 20/8, 2018 at 21:10 Comment(1)
you declare but do not use authz. Also no need to assign and echo result, you could just let jq output.Rustproof
G
2

Docker made a huge refactor of the registry: registry v2.0.

With this brand new version, comes a new authentication system so the basic auth of v1.0 will not work anymore.

You can find more details about the v2.0 auth here: https://docs.docker.com/v1.6/registry/spec/auth/token/

As v1.0 is deprecated, you should move forward to registry v2.0.

Grimmett answered 12/2, 2016 at 16:31 Comment(0)
F
2

Here's a Bash script to do just that. Save it to a file named docker-hub-tags-list and run it like this:

docker-hub-tags-list markriggins/todowrangler

But you need to be logged in via docker login first. And you will need to install the JSON tool http://trentm.com/json/ which is a very cool tool for parsing JSON on the command line.

#!/usr/bin/env bash

REPOSITORY=${REPOSITORY:-$1}
REGISTRY=${REGISTRY:-docker.io}

#
#  Docker funcs
#
    d__docker_relative_repository_name_from_URL() {
        # Given $REGISTRY/repo/path:tag, return the repo/path
        set +o pipefail
        echo ${1-} | sed -e "s|^$REGISTRY/||" | cut -d: -f1
    }

    d___version_sort() {
        # Read stdin, sort by version number descending, and write stdout
        # It assumes X.Y.Z version numbers

        # This will sort tags like pr-3001, pr-3002 to the END of the list
        # and tags like 2.1.4 BEFORE 2.1.4-gitsha

        sort -s -t- -k 2,2nr |  sort -t. -s -k 1,1nr -k 2,2nr -k 3,3nr -k 4,4nr
    }

    d__basic_auth() {
        #
        # Read basic authentication credentials from `docker login`
        #
        cat ~/.docker/config.json | json '.auths["https://index.docker.io/v1/"].auth'
    }


    d__registry__tags_list() {

        # Return a list of available tags for the given repository sorted
        # by version number, descending
        #
        # Get tags list from dockerhub using the v2 API and an auth.docker token

        local rel_repository=$(d__docker_relative_repository_name_from_URL ${1})
        [ -z "$rel_repository" ] && return

        local TOKEN=$(curl -s -H "Authorization: Basic $(d__basic_auth)" \
                       -H 'Accept: application/json' \
                       "https://auth.docker.io/token?service=registry.docker.io&scope=repository:$rel_repository:pull" | json .token)


        curl -s -H "Authorization: Bearer $TOKEN" -H "Accept: application/json" \
                "https://index.docker.io/v2/$rel_repository/tags/list" |
                json .tags |
                json -a |
                d___version_sort
    }

d__registry__tags_list $REPOSITORY
Festival answered 9/7, 2016 at 2:23 Comment(0)
S
2

private image repositories, v2 API

A version that works with private and public repositories, written in vanilla Bourne shell (including, but not limited to Bash), and using the v2 API, lives at https://gist.github.com/nealey/86da928cdb5c21a4edc1be2ba7b845e3

You can run it like:

$ docker-tags.sh alpine
$ docker-tags.sh ceph/daemon
$ docker-tags.sh quay.io/coreos/dnsmasq

It lists all versions, one per line.

#! /bin/sh

image="$1"; shift
if [ -z "$image" ] || [ "$image" == "--help" ]; then
    echo "Usage: $0 IMAGE"
    echo
    echo "Prints all tags associated with IMAGE in a docker repository"
    exit 1
fi

case "$image" in
    */*/*)
        host=${image%%/*/*}
        path=${image#*/}
        ;;
    */*)
        host=index.docker.io
        path=$image
        ;;
    *)
        host=index.docker.io
        path=library/$image
        ;;
esac

tags_uri=https://$host/v2/$path/tags/list

##
## Figure out who hands out tokens by doing an unauthenticated request
##
extract () {
    # XXX: This can't handle values with commas in them
    echo -n "$2" | awk -v f="$1" 'BEGIN {RS=","; FS="=\"|\"$";} ($1 == f) { print $2; }'
}
auth=$(curl --silent -I $tags_uri | sed -n 's/^Www-Authenticate: Bearer //p' | tr -d '\r')
if [ -n "$auth" ]; then
    realm=$(extract realm "$auth")
    service=$(extract service "$auth")
    scope=$(extract scope "$auth")
    ## Now fetch a token
    token=$(curl --silent --get --data-urlencode "service=$service" --data-urlencode "scope=$scope" $realm | jq  -r '.token')
    auth_header="Authorization: Bearer $token"
fi

## Finally, list versions
curl -s --header "$auth_header" "$tags_uri" | jq -r '.tags[]'
Saurian answered 23/1, 2019 at 0:39 Comment(0)
S
0

Thanks Neale Picket for your script. It wasn't working for me for private repositories, so I edited it a little (and also fixed a problem with case sensitive on headers detection)

This one asks for your Dockerhub user and password at the very beginning, and use it to make and authenticated request to Dockehuv API.

Gist: https://gist.github.com/juanlb/b959354cc289dd9962e9f57dee4ac063

Surcharge answered 3/6, 2021 at 16:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.