Can I get an image digest without downloading the image? - docker
Similar to the question "What´s the sha256 code of a docker image?", I would like to find the digest of a Docker image. I can see the digest when I download an image:
$ docker pull waisbrot/wait:latest
latest: Pulling from waisbrot/wait
Digest: sha256:6f2185daa4ab1711181c30d03f565508e8e978ebd0f263030e7de98deee5f330
Status: Image is up to date for waisbrot/wait:latest
$
Another question, What is the Docker registry v2 API endpoint to get the digest for an image has an answer suggesting the Docker-Content-Digest header.
I can see that there is a Docker-Content-Digest header when I fetch the manifest for the image:
$ curl 'https://auth.docker.io/token?service=registry.docker.io&scope=repository:waisbrot/wait:pull' -H "Authorization: Basic ${username_password_base64}"
# store the resulting token in DT
$ curl -v https://registry-1.docker.io/v2/waisbrot/wait/manifests/latest -H "Authorization: Bearer $DT" -XHEAD
* Trying 52.7.141.30...
* Connected to registry-1.docker.io (52.7.141.30) port 443 (#0)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate: *.docker.io
* Server certificate: RapidSSL SHA256 CA - G3
* Server certificate: GeoTrust Global CA
> GET /v2/waisbrot/wait/manifests/latest HTTP/1.1
> Host: registry-1.docker.io
> User-Agent: curl/7.43.0
> Accept: */*
> Authorization: Bearer LtVRw-etc-etc-etc
>
< HTTP/1.1 200 OK
< Content-Length: 4974
< Content-Type: application/vnd.docker.distribution.manifest.v1+prettyjws
< Docker-Content-Digest: sha256:128c6e3534b842a2eec139999b8ce8aa9a2af9907e2b9269550809d18cd832a3
< Docker-Distribution-Api-Version: registry/2.0
< Etag: "sha256:128c6e3534b842a2eec139999b8ce8aa9a2af9907e2b9269550809d18cd832a3"
< Date: Wed, 07 Sep 2016 16:37:15 GMT
< Strict-Transport-Security: max-age=31536000
However, this header isn't the same. The pull command got me 6f21 and the header shows 128c. Further, the pull command doesn't work for that digest:
$ docker pull waisbrot/wait#sha256:128c6e3534b842a2eec139999b8ce8aa9a2af9907e2b9269550809d18cd832a3
Error response from daemon: manifest unknown: manifest unknown
whereas things work as I want when I have the correct digest:
$ docker pull waisbrot/wait#sha256:6f2185daa4ab1711181c30d03f565508e8e978ebd0f263030e7de98deee5f330 12:46 waisbrot#influenza
sha256:6f2185daa4ab1711181c30d03f565508e8e978ebd0f263030e7de98deee5f330: Pulling from waisbrot/wait
Digest: sha256:6f2185daa4ab1711181c30d03f565508e8e978ebd0f263030e7de98deee5f330
Status: Image is up to date for waisbrot/wait#sha256:6f2185daa4ab1711181c30d03f565508e8e978ebd0f263030e7de98deee5f330
What I'm looking for is a way to translate the latest tag (which changes all the time) into a fixed digest that I can reliably pull. But I don't want to actually pull it down in order to do this translation.
edit 2022-10-04:
# INPUT
REPO=waisbrot/wait
user=my-user
password=my-password
# Get TOKEN
username_password_base64=$(echo -n $user:$password | base64)
TOKEN=$(curl -s -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
-H "Authorization: Basic ${username_password_base64}" \
'https://auth.docker.io/token?service=registry.docker.io&scope=repository:waisbrot/wait:pull' \
| jq -r .token)
# GET Digest from v2 API
curl -s -D - -H "Authorization: Bearer $TOKEN" \
https://registry-1.docker.io/v2/waisbrot/wait/manifests/latest 2>&1 \
| grep docker-content-digest \
| cut -d' ' -f2
original answer:
For newer versions of Docker, the inspect command provides the correct value (requires the image to have been pulled as Jan Hudec has pointed out in the comments):
docker inspect --format='{{index .RepoDigests 0}}' waisbrot/wait
For older versions, fetch the value from the repository following this example with the main Docker repo:
curl -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
-H "Authorization: Basic ${username_password_base64}" \
'https://auth.docker.io/token?service=registry.docker.io&scope=repository:waisbrot/wait:pull'
Naive attempts to fetch that value fail because the default content-type being selected by the server is application/vnd.docker.distribution.manifest.v1+prettyjws (a v1 manifest) and you need to v2 manifest. Therefore, you need to set the Accept header to application/vnd.docker.distribution.manifest.v2+json.
This is how you do it today using a V2 manifest.
docker manifest inspect <REMOTE IMAGE>:<TAG> -v
Your output is JSON:
{
...
"Descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:d13e102941a9f7bd417440f62f9cb29de35f6acb13a26cbf6a34f4c7340f0b63",
"size": 3255,
"platform": {
"architecture": "amd64",
"os": "linux"
}
},
...
}
With 2 http requests, you can get it. The first one to get an authentication token, and the second to get the image digest list by architecture and variant:
token=$(curl --silent "https://auth.docker.io/token?scope=repository:$image:pull&service=registry.docker.io" | jq -r '.token')
curl -s --header "Accept: application/vnd.docker.distribution.manifest.list.v2+json" --header "Authorization: Bearer ${token}" "https://registry-1.docker.io/v2/$image/manifests/$tag" | jq -r '.manifests|.[]| "\(.digest) \(.platform.architecture) \(.platform.variant)"'
Example with:
image=library/nginx
tag=stable-alpine
sha256:8853c7e938c2aa5d9d7439e698f0e700f058df8414a83134a09fcbb68bb0707a amd64 null
sha256:dbcd23f95b94018fe72bfdb356e40f4ae8b95063883f3456fedaed1c02204ed4 arm v6
sha256:d3670edcd50bb07cae303767426adf9bc7ba0219736148d30e6f30dd4e08695c arm v7
sha256:0bcd76faa141e4fa37e875834b3994261e0cfc94b7233ac84896381315b845ca arm64 v8
sha256:da8e62ddb3fab89ff4fa0271dbe230f849ab53402a71338503952437dcda1026 386 null
sha256:269bf99e100294b6b75fbdecf7b4ddbef8b29ea0a953e2e904452a50dbc923ab ppc64le null
sha256:103da50956034c157abeffbc869e2e38a4fabbf913bed8ae6ae7c59e646b28a1 s390x null
I encountered a task recently that required viewing the sha256 digest without necessarily pulling the image. The tool skopeo makes the registry API calls so you don't need to pull the image.
For example,
$ skopeo inspect --creds "username:password" docker://waisbrot/wait:latest
You could then pipe this to jq if you want to get just the digest value.
$ skopeo inspect --creds "username:password" \
docker://waisbrot/wait:latest | jq -r '.Digest'
sha256:6f2185daa4ab1711181c30d03f565508e8e978ebd0f263030e7de98deee5f330
I realise this issue is answered however either I am missing something or the current version of AWS ECR registry service does not work as expected.
When trying to get the digest from AWS ECR using either HEAD and also trying to switch the content-type does not return a digest value that I can use to pull an image using the registry Api.
To get this digest you have to get the manifest for the tag you are interested in and calculate the sha256 of the response Json as is, including the formatting, without the signature section
I struggled with this also. Here is a C# (dotnet core 5.0) implementation if anyone is intersted:
/**
TOKEN=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:waisbrot/wait:pull" | jq -r .token)
curl -s -D - -H "Authorization: Bearer $TOKEN" -H "Accept: application/vnd.docker.distribution.manifest.v2+json" https://index.docker.io/v2/waisbrot/wait/manifests/latest
*/
private string GetRemoteImageDigest(string image, string tag) {
using HttpClient client = new ();
var url = string.Format($"https://auth.docker.io/token?service=registry.docker.io&scope=repository:{image}:pull");
//var response = client.Send(new HttpRequestMessage(HttpMethod.Get, url));
var result = client.GetStringAsync(url);
var drt = JsonSerializer.Deserialize<DockerRegistryToken>(result.Result);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", drt.Token);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/vnd.docker.distribution.manifest.v2+json"));
var response = client.GetAsync(string.Format($"https://index.docker.io/v2/{image}/manifests/{tag}"));
var headers = response.Result.Headers;
IEnumerable<string> values;
headers.TryGetValues("Docker-Content-Digest", out values);
return values.FirstOrDefault();
}
DockerRegistryToken is defined as:
public class DockerRegistryToken{
[JsonPropertyName("token")]
public string Token { get; set; }
/// always null
[JsonPropertyName("access_token")]
public string AccessToken {get; set; }
[JsonPropertyName("expires_in")]
public int ExpiresInSeconds { get; set; }
[JsonPropertyName("issued_at")]
public DateTime IssuedAt { get; set; }
}
As mentioned in other answers, this digest did not match because you attempted to curl without an Accept header, and so the registry triggered a fallback to an older v1 image manifest:
< Content-Type: application/vnd.docker.distribution.manifest.v1+prettyjws
< Docker-Content-Digest: sha256:128c6e3534b842a2eec139999b8ce8aa9a2af9907e2b9269550809d18cd832a3
You can query Hub with curl using a script like:
#!/bin/sh
ref="${1:-library/ubuntu:latest}"
sha="${ref#*#}"
if [ "$sha" = "$ref" ]; then
sha=""
fi
wosha="${ref%%#*}"
repo="${wosha%:*}"
tag="${wosha##*:}"
if [ "$tag" = "$wosha" ]; then
tag="latest"
fi
cto="application/vnd.oci.image.index.v1+json"
ctol="application/vnd.oci.image.manifest.v1+json"
ctd="application/vnd.docker.distribution.manifest.v2+json"
ctdl="application/vnd.docker.distribution.manifest.list.v2+json"
token=$(curl -sL "https://auth.docker.io/token?service=registry.docker.io&scope=repository:${repo}:pull" \
| jq -r '.token')
curl -H "Accept: ${cto}" -H "Accept: ${ctol}" -H "Accept: ${ctd}" -H "Accept: ${ctdl}" \
-H "Authorization: Bearer $token" \
-I -sL "https://registry-1.docker.io/v2/${repo}/manifests/${sha:-$tag}"
However, that's limited since it's specific to Hub, and you still need to parse the headers. From the skopeo output, it's still pulling the entire manifest rather than a HEAD request, which will count against Hub rate limits.
Instead my two preferred tools for this are go-containerregistry/crane and regclient/regctl (I'm the author of the latter). Each has a digest command which automatically handles auth to different registries, includes the needed Accept headers, and parses the output to just the digest which is useful for scripting:
$ regctl image digest busybox
sha256:3b3128d9df6bbbcc92e2358e596c9fbd722a437a62bafbc51607970e9e3b8869
$ crane digest busybox
sha256:3b3128d9df6bbbcc92e2358e596c9fbd722a437a62bafbc51607970e9e3b8869
To avoid installing other tools, docker now has docker buildx imagetools inspect, but similar to skopeo, this is pulling the entire manifest rather than a HEAD request:
$ docker buildx imagetools inspect busybox
Name: docker.io/library/busybox:latest
MediaType: application/vnd.docker.distribution.manifest.list.v2+json
Digest: sha256:3b3128d9df6bbbcc92e2358e596c9fbd722a437a62bafbc51607970e9e3b8869
...
$ docker buildx imagetools inspect busybox --format '{{json .}}' | jq -r .manifest.digest
sha256:3b3128d9df6bbbcc92e2358e596c9fbd722a437a62bafbc51607970e9e3b8869
example for reg which requires redirect (curl follow 302)
REGISTRY_ADDRESS='registry.access.redhat.com'
image='ubi8/openjdk-17-runtime'
curl --silent -L \
--header "Accept: application/vnd.docker.distribution.manifest.v2+json" \
"https://$REGISTRY_ADDRESS/v2/$image/manifests/latest" |
jq -r '.config.digest'
Following up on ByteFlinger's suggestion, which did not have an example, I tried this, and this is how to calculate it:
$ docker-ls tag -registry https://myregistry.net:5000
spicysomtam/zookeeper:latest
requesting manifest . done
repository: spicysomtam/zookeeper
tagName: latest
digest: sha256:bd5dd80253171e4dffccbea7c639c90a63d5424aa2d7fe655aea766405c83036
$ curl -ns -H "Accept:
application/vnd.docker.distribution.manifest.v2+json" -X GET
https://myregistry.net:5000/v2/spicysomtam/zookeeper/manifests/latest|sha256sum
bd5dd80253171e4dffccbea7c639c90a63d5424aa2d7fe655aea766405c83036 -
$ docker images --digests |grep zookeeper
myregistry.net:5000/spicysomtam/zookeeper latest sha256:bd5dd80253171e4dffccbea7c639c90a63d5424aa2d7fe655aea766405c83036 a983e71ca22d 29 hours ago 584MB
You can get this using docker inspect:
docker inspect --format='{{index .RepoDigests 0}}' ${IMAGE_NAME}
Docs: https://docs.docker.com/engine/reference/commandline/inspect/
This has been in place since at least v1.9.
Related
How to make a HEAD request to Docker Hub API to get the manifest?
I need to reach manifests of a lot of images on Docker hub, but every GET request for getting manifest is counted as a pull, as a result, I am restricted by the rate limits of docker hub. Is there a way to get the manifest with a HEAD request instead of GET from the API? Edit: From Docker registry API documentation : GET /v2//manifests/: Fetch the manifest identified by name and reference where reference can be a tag or digest. A HEAD request can also be issued to this endpoint to obtain resource information without receiving all data. So I assume we can get related information with an HEAD request.
A shell script to do that looks like: #!/bin/sh ref="${1:-library/ubuntu:latest}" sha="${ref#*#}" if [ "$sha" = "$ref" ]; then sha="" fi wosha="${ref%%#*}" repo="${wosha%:*}" tag="${wosha##*:}" if [ "$tag" = "$wosha" ]; then tag="latest" fi apio="application/vnd.oci.image.index.v1+json" apiol="application/vnd.oci.image.manifest.v1+json" apid="application/vnd.docker.distribution.manifest.v2+json" apidl="application/vnd.docker.distribution.manifest.list.v2+json" token=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:${repo}:pull" \ | jq -r '.token') curl -H "Accept: ${apio}" -H "Accept: ${apiol}" -H "Accept: ${apid}" -H "Accept: ${apidl}" \ -H "Authorization: Bearer $token" \ -I -s "https://registry-1.docker.io/v2/${repo}/manifests/${sha:-$tag}" Note that the head request only shows the headers, and the most useful one is docker-content-digest so you can get the digest for a specific tag: HTTP/1.1 200 OK content-length: 1416 content-type: application/vnd.docker.distribution.manifest.list.v2+json docker-content-digest: sha256:20fa2d7bb4de7723f542be5923b06c4d704370f0390e4ae9e1c833c8785644c1 docker-distribution-api-version: registry/2.0 etag: "sha256:20fa2d7bb4de7723f542be5923b06c4d704370f0390e4ae9e1c833c8785644c1" date: Thu, 08 Sep 2022 17:45:42 GMT strict-transport-security: max-age=31536000 ratelimit-limit: 100;w=21600 ratelimit-remaining: 100;w=21600 docker-ratelimit-source: 68.100.24.47 If you want to do this for other registries, you'll need to adjust the authentication. Both go-containerregistry's crane and regclient's regctl tools have image digest commands that handle the authentication and return just the digest.
Find docker tags that are synonyms of the "latest" tag via the REST API
I have a container image called troubleshooting. There are 5 different versions of the image in the my private repository. (Meaning 5 different image digests listed.) The most recent image has a tag on it called latest. I need a way to get the other tags on that same image. I am doing this in a build script, so I would prefer to keep it through the REST API that docker has. I tried used the /v2/myrepository/myimage/tags/list endpoint, but it lists all the tags without breaking them up by digest. Is there a way to get tags broken up by digest? (Using the REST API?)
At present, you would need to perform a HEAD request on each tag, with the proper accept headers, to get the digest. There are suggestions to extend OCI's distribution-spec with a better tag API, but that will take some time to get approved and then implemented by the various registries. Here's an example script for querying Docker Hub for either a docker manifest or manifest list (there are additional media types available for things like OCI image/index): #!/bin/sh ref="${1:-library/ubuntu:latest}" sha="${ref#*#}" if [ "$sha" = "$ref" ]; then sha="" fi wosha="${ref%%#*}" repo="${wosha%:*}" tag="${wosha##*:}" if [ "$tag" = "$wosha" ]; then tag="latest" fi api="application/vnd.docker.distribution.manifest.v2+json" apil="application/vnd.docker.distribution.manifest.list.v2+json" token=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:${repo}:pull" \ | jq -r '.token') curl -H "Accept: ${api}" -H "Accept: ${apil}" \ -H "Authorization: Bearer $token" \ -I -s "https://registry-1.docker.io/v2/${repo}/manifests/${sha:-$tag}" And the resulting headers that includes the docker-content-digest field: $ ./manifest-v2-head.sh HTTP/1.1 200 OK content-length: 1416 content-type: application/vnd.docker.distribution.manifest.list.v2+json docker-content-digest: sha256:a0d9e826ab87bd665cfc640598a871b748b4b70a01a4f3d174d4fb02adad07a9 docker-distribution-api-version: registry/2.0 etag: "sha256:a0d9e826ab87bd665cfc640598a871b748b4b70a01a4f3d174d4fb02adad07a9" date: Fri, 08 Oct 2021 18:04:26 GMT strict-transport-security: max-age=31536000 ratelimit-limit: 100;w=21600 ratelimit-remaining: 100;w=21600 docker-ratelimit-source: 68.100.24.47
How to Get All Tags from Docker Hub (Private Repositories) as Shell Script
I have one shell script when i execute it showing only 64 tags from 300 tags docker hub. Here is the below command which i'm executing in shell script through curl. IMAGE_TAGS=$(curl -s -H "Authorization: JWT ${HUB_TOKEN} https://hub.docker.com/v2/repositories/$username/issues/tags/?page_size=300" | jq --raw-output '.results[] | .name') Even after giving page_size also it is not showing my all tags Note :- Tags using for Private Repositories Please help me how can i solve it
Try API version 1 which help me to get all the tags https://registry.hub.docker.com/v1/repositories/mysql/tags open in browser and you can modify it as per your need Or have a look to Github https://gist.github.com/robv8r/fa66f5e0fdf001f425fe9facf2db6d49 This is exactly what you want UPDATE Add this in a shell script file #!/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 } docker-tags "<YOUR_DOCKER_IMAGE_NAME>" Replace <YOUR_DOCKER_IMAGE_NAME> with your docker image. have a look to this for more info Listing the tags of a Docker image on a Docker hub through the HTTP API
How to determine the Docker image ID for a tag via Docker Hub API?
Given a tag `latest`, we want to find out another tag with the same image ID on Docker Hub. Here is how to find out all tags for a repo with the Docker Hub API v2: TOKEN=$(curl -s -H "Content-Type: application/json" -X POST -d '{"username": "'${UNAME}'", "password": "'${UPASS}'"}' https://hub.docker.com/v2/users/login/ | jq -r .token) curl -s -H "Authorization: JWT ${TOKEN}" https://hub.docker.com/v2/repositories/fluent/fluentd/tags/?page_size=100 | jq (See gist.github.com/kizbitz) Unfortunately, it doesn't contain the image ID but always a `null` value for this key: $ curl -s -H "Authorization: JWT ${TOKEN}" https://hub.docker.com/v2/repositories/fluent/fluentd/tags/?page_size=100 | jq { "count": 36, "next": null, "previous": null, "results": [ ... { "name": "v0.14.11", "full_size": 11964464, "id": 7084687, "repository": 219785, "creator": 2923, "last_updater": 2923, "last_updated": "2016-12-27T07:16:41.294807Z", "image_id": null, "v2": true, "platforms": [ 5 ] }, ... Unfortunately, the image ID is something different than the `id` in the JSON above. $ docker images | grep fluent docker.io/fluent/fluentd v0.14.11 1441d57beff9 3 weeks ago 38.25 MB Theoretically, it should be possible to access the Docker Manifests and along with the the image ID with this Docker Registry call but it doesn't help either: $ curl -s -H "Authorization: JWT ${TOKEN}" "https://registry.hub.docker.com/v2/fluent/fluentd/manifests/latest" {"errors":[{"code":"UNAUTHORIZED","message":"authentication required","detail":[{"Type":"repository","Name":"fluent/fluentd","Action":"pull"}]}]} (See stackoverflow.com) Here is a similar issue in the Docker GitHub repo but I still cannot figure out the solution: https://github.com/docker/distribution/issues/1490 . P.S.: Here is my Docker version with which I tried to push a test image: $ docker version Client: Version: 1.12.6 API version: 1.24 Package version: docker-common-1.12.6-5.git037a2f5.fc25.x86_64 Go version: go1.7.4 Git commit: 037a2f5/1.12.6 Built: Wed Jan 18 12:11:29 2017 OS/Arch: linux/amd64
Docker Registry API v2 uses image digest instead of image ID to distinguish image identity. The image digest can be obtained from Docker-Content-Digest of the HTTP response header by making the following API call: $ REPOSITORY=fluent/fluentd $ TOKEN=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:$REPOSITORY:pull" | jq -r .token) $ curl -s -D - -H "Authorization: Bearer $TOKEN" -H "Accept: application/vnd.docker.distribution.manifest.v2+json" https://index.docker.io/v2/$REPOSITORY/manifests/latest HTTP/1.1 200 OK Content-Length: 1982 Content-Type: application/vnd.docker.distribution.manifest.v2+json Docker-Content-Digest: sha256:eaea1edffc34cff3b5e31ee738ea56e46326f90731b4139a19948814a4f0a4db Docker-Distribution-Api-Version: registry/2.0 Etag: "sha256:eaea1edffc34cff3b5e31ee738ea56e46326f90731b4139a19948814a4f0a4db" Date: Tue, 24 Jan 2017 13:34:53 GMT Strict-Transport-Security: max-age=31536000 ... All tags can be obtained with the following API call: $ curl -s -H "Authorization: Bearer $TOKEN" https://index.docker.io/v2/$REPOSITORY/tags/list {"name":"fluent/fluentd","tags":["edge-onbuild","edge","jemalloc","latest-onbuild","latest","onbuild","stable-onbuild","stable","ubuntu-base","v0.12-latest-onbuild","v0.12-latest","v0.12-onbuild","v0.12.16","v0.12.18","v0.12.19","v0.12.20","v0.12.21","v0.12.23","v0.12.24","v0.12.26-2","v0.12.26-onbuild","v0.12.26","v0.12.27-onbuild","v0.12.27","v0.12.28-onbuild","v0.12.28","v0.12.29-onbuild","v0.12.29","v0.12.30-onbuild","v0.12.30","v0.12.31-onbuild","v0.12.31","v0.12","v0.14-latest-onbuild","v0.14-latest","v0.14-onbuild","v0.14.1","v0.14.10-onbuild","v0.14.10","v0.14.11-onbuild","v0.14.11","v0.14.2","v0.14.6","v0.14.8","v0.14"]} Based on the above, to find the same digest as a specific tag, it will be a script like the following. #!/bin/bash REPOSITORY=$1 TARGET_TAG=$2 # get authorization token TOKEN=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:$REPOSITORY:pull" | jq -r .token) # find all tags ALL_TAGS=$(curl -s -H "Authorization: Bearer $TOKEN" https://index.docker.io/v2/$REPOSITORY/tags/list | jq -r .tags[]) # get image digest for target TARGET_DIGEST=$(curl -s -D - -H "Authorization: Bearer $TOKEN" -H "Accept: application/vnd.docker.distribution.manifest.v2+json" https://index.docker.io/v2/$REPOSITORY/manifests/$TARGET_TAG | grep Docker-Content-Digest | cut -d ' ' -f 2) # for each tags for tag in ${ALL_TAGS[#]}; do # get image digest digest=$(curl -s -D - -H "Authorization: Bearer $TOKEN" -H "Accept: application/vnd.docker.distribution.manifest.v2+json" https://index.docker.io/v2/$REPOSITORY/manifests/$tag | grep Docker-Content-Digest | cut -d ' ' -f 2) # check digest if [[ $TARGET_DIGEST = $digest ]]; then echo "$tag $digest" fi done The result is as follows: $ ./find_same_digest.sh fluent/fluentd latest latest sha256:eaea1edffc34cff3b5e31ee738ea56e46326f90731b4139a19948814a4f0a4db stable sha256:eaea1edffc34cff3b5e31ee738ea56e46326f90731b4139a19948814a4f0a4db v0.12.31 sha256:eaea1edffc34cff3b5e31ee738ea56e46326f90731b4139a19948814a4f0a4db v0.12 sha256:eaea1edffc34cff3b5e31ee738ea56e46326f90731b4139a19948814a4f0a4db If you want to check the digest of the local image, you can get it with docker images --digests: $ docker images --digests | grep fluentd fluent/fluentd latest sha256:eaea1edffc34cff3b5e31ee738ea56e46326f90731b4139a19948814a4f0a4db 1788ee7dcfcc 14 hours ago 35.41 MB
The above answer is great! In addition, if you want to use this on a private repo, you need to add basic auth with your registry user credentials, and the additional scope parameter 'account=' (see http://www.cakesolutions.net/teamblogs/docker-registry-api-calls-as-an-authenticated-user)
delete image from docker registry v2
the Docker Registry v2 has an API endpoint to delete an image DELETE /v2/<name>/manifests/<reference> https://github.com/docker/distribution/blob/master/docs/spec/api.md#deleting-an-image However the doc says: For deletes, reference must be a digest or the delete will fail. Indeed, using a tag does not work and returns a 405 Operation Not Supported The problem is, there doesn't seem to be any endpoint to get the digest of an image. The endpoints to list images, and tags only list those. Trying to get the manifest with GET /v2/<name>/manifests/<reference> using the tag as <reference>I see that a Docker-Content-Digest header is set with a digest which the doc says is Docker-Content-Digest: Digest of the targeted content for the request. while the body contains a bunch of blobSum: <digest> If I try using the Header digest value, with GET /v2/<name>/manifests/<reference> and the digest as <reference>, I get a 404. the digest looks like: sha256:6367f164d92eb69a7f4bf4cab173e6b21398f94984ea1e1d8addc1863f4ed502 and I tried with and without the sha256 prefix. but no luck So how am I supposed to get the digest of the image I want to delete, to delete it?
curl -u login:password -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -X GET https://registry.private.com/v2/<name>/manifests/<tag> json > config > digest
Not a trivial operation in Docker API right now but I hope this procedure helps: Create a file and give it a name, for me it will be delete-image.sh: #!/bin/bash # Inspired by: https://gist.github.com/jaytaylor/86d5efaddda926a25fa68c263830dac1 set -o errexit if [ -z "$1" ] then echo "Error: The image name arg is mandatory" exit 1 fi registry='localhost:5000' name=$1 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' \ )" Give the permission to that file so that it can be executed; sudo chmod u+x ./delete-image.sh ./delete-image.sh <your-image-name> After deleting the image, collect the garbage; docker exec -it registry.localhost bin/registry \ garbage-collect /etc/docker/registry/config.yml Now delete the folder for that image (and I'm assuming that you created a volume previously); sudo rm -rf ${HOME}/registry/docker/registry/v2/repositories/<your-image-name> If you have not created a volume, you may have to enter the container to delete that folder. But, in any case, it's a good idea to restart the container; docker restart registry.localhost Procedure not recommended for production environments. I hope that we will have better support for these operations natively in the Docker API in the future.