When an image has been pushed to registry V2, does the image ID will be pushed to registry as well? Is that possible to get image ID for a certain repository from V2 registry?
If the image was pushed with Docker Client 1.10 or above, you can obtain the image ID from the registry with
GET /v2/<image>/manifests/<tag>
Your request must include the header
Accept: application/vnd.docker.distribution.manifest.v2+json
In the response, the image ID will be in the Content-Docker-Digest
Response header.
$server
, $repo
, and $tag
–
Mweru [ Updated answer in 2020-11 ]
There are lots of sha's to deal with when using docker images. Each filesystem layer has a unique sha, and that gets updated when the layer is compressed and stored on the registry. There's a sha computed on the json object representing the image configuration, and this is what you see when you lookup the image id locally with:
$ docker inspect busybox:latest --format '{{ .ID }}'
sha256:f0b02e9d092d905d0d87a8455a1ae3e9bb47b4aa3dc125125ca5cd10d6441c9f
There's a sha for a single platform's manifest on the registry. This manifest includes a pointer to the image configuration and the various layers. And there's also a sha for the multi-platform manifest that points to each of those individual platforms. Lets dig into those. First here's a script I'll use to query the Docker Hub registry with anonymous requests:
$ cat manifest-v2.sh
#!/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" \
-s "https://registry-1.docker.io/v2/${repo}/manifests/${sha:-$tag}" | jq .
Next, lets pull the manifest for the latest tag:
$ ./manifest-v2.sh library/busybox:latest
{
"manifests": [
{
"digest": "sha256:c9249fdf56138f0d929e2080ae98ee9cb2946f71498fc1484288e6a935b5e5bc",
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "amd64",
"os": "linux"
},
"size": 527
},
{
"digest": "sha256:a7c572c26ca470b3148d6c1e48ad3db90708a2769fdf836aa44d74b83190496d",
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "arm",
"os": "linux",
"variant": "v5"
},
"size": 527
},
...
The result is a manifest list, lets pull the sha for just the amd64 platform:
$ ./manifest-v2.sh library/busybox@sha256:c9249fdf56138f0d929e2080ae98ee9cb2946f71498fc1484288e6a935b5e5bc
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"config": {
"mediaType": "application/vnd.docker.container.image.v1+json",
"size": 1493,
"digest": "sha256:f0b02e9d092d905d0d87a8455a1ae3e9bb47b4aa3dc125125ca5cd10d6441c9f"
},
"layers": [
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 764619,
"digest": "sha256:9758c28807f21c13d05c704821fdd56c0b9574912f9b916c65e1df3e6b8bc572"
}
]
}
In there we have a single layer and the config object, and the sha on that config with the application/vnd.docker.container.image.v1+json
media type matches our image id sha256:f0b02e9d092d9...
. This is easier to pick out with the v2 output from the registry which is why the manifest script inserts the Accept
headers.
I'd caution that I don't believe it is guaranteed to match, YMMV, IANAL, etc. I could foresee docker adding/removing fields that would get ignored by the different versions of the docker engine. So I'd avoid any hard dependency of this behavior.
Note that this sha is not the same as the sha you would use to uniquely identify an image on the registry for pulling images. For that, you want the manifest sha, and if there's a manifest list you should use that. You can see this sha with just a HEAD request when resolving the tag (using the -I
parameter to curl):
$ cat manifest-v2-head.sh
#!/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
# echo "Looking up repo $repo, ${sha:-$tag}"
# api="application/vnd.oci.image.index.v1+json"
# api="application/vnd.oci.image.manifest.v1+json"
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}"
$ ./manifest-v2-head.sh library/busybox:latest
HTTP/1.1 200 OK
Content-Length: 2080
Content-Type: application/vnd.docker.distribution.manifest.list.v2+json
Docker-Content-Digest: sha256:a9286defaba7b3a519d585ba0e37d0b2cbee74ebfe590960b0b1d6a5e97d1e1d
Docker-Distribution-Api-Version: registry/2.0
Etag: "sha256:a9286defaba7b3a519d585ba0e37d0b2cbee74ebfe590960b0b1d6a5e97d1e1d"
Date: Wed, 18 Nov 2020 14:38:59 GMT
Strict-Transport-Security: max-age=31536000
RateLimit-Limit: 250;w=21600
RateLimit-Remaining: 250;w=21600
From the above, you could docker pull busybox@sha:a9286d...
.
All of the commands here are Docker Hub specific. For working with other registries, I have a regctl
command available in my regclient project that handles auth and API calls to other registries:
$ regctl image manifest busybox
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"config": {
"mediaType": "application/vnd.docker.container.image.v1+json",
"size": 1493,
"digest": "sha256:f0b02e9d092d905d0d87a8455a1ae3e9bb47b4aa3dc125125ca5cd10d6441c9f"
},
"layers": [
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 764619,
"digest": "sha256:9758c28807f21c13d05c704821fdd56c0b9574912f9b916c65e1df3e6b8bc572"
}
]
}
$ regctl image digest busybox --list
sha256:a9286defaba7b3a519d585ba0e37d0b2cbee74ebfe590960b0b1d6a5e97d1e1d
$ regctl image digest busybox
sha256:c9249fdf56138f0d929e2080ae98ee9cb2946f71498fc1484288e6a935b5e5bc
Original answer:
The image id itself is not stored in any registry API accessible location, here's an example using a local registry:
bash$ docker run -d -p 5000:5000 --restart=always --name registry registry:2
Unable to find image 'registry:2' locally
2: Pulling from library/registry
...
bash$ docker tag busybox localhost:5000/busybox
bash$ docker push localhost:5000/busybox
The push refers to a repository [localhost:5000/busybox]
5f70bf18a086: Pushed
...
bash$ curl http://localhost:5000/v2/busybox/tags/list
{"name":"busybox","tags":["latest"]}
bash$ curl http://localhost:5000/v2/busybox/manifests/latest
{
"schemaVersion": 1,
"name": "busybox",
"tag": "latest",
"architecture": "amd64",
"fsLayers": [
{
"blobSum": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"
},
{
"blobSum": "sha256:385e281300cc6d88bdd155e0931fbdfbb1801c2b0265340a40481ee2b733ae66"
}
],
"history": [
{
"v1Compatibility": "{\"architecture\":\"amd64\",\"config\":{\"Hostname\":\"156e10b83429\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":[\"sh\"],\"Image\":\"56ed16bd6310cca65920c653a9bb22de6b235990dcaa1742ff839867aed730e5\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":null,\"Labels\":{}},\"container\":\"5f8098ec29947b5bea80483cd3275008911ce87438fed628e34ec0c522665510\",\"container_config\":{\"Hostname\":\"156e10b83429\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) CMD [\\\"sh\\\"]\"],\"Image\":\"56ed16bd6310cca65920c653a9bb22de6b235990dcaa1742ff839867aed730e5\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":null,\"Labels\":{}},\"created\":\"2016-03-18T18:22:48.810791943Z\",\"docker_version\":\"1.9.1\",\"id\":\"437595becdebaaaf3a4fc3db02c59a980f955dee825c153308c670610bb694e1\",\"os\":\"linux\",\"parent\":\"920777304d1d5e337bc59877253e946f224df5aae64c72538672eb74637b3c9e\"}"
},
{
"v1Compatibility": "{\"id\":\"920777304d1d5e337bc59877253e946f224df5aae64c72538672eb74637b3c9e\",\"created\":\"2016-03-18T18:22:48.262403239Z\",\"container_config\":{\"Cmd\":[\"/bin/sh -c #(nop) ADD file:47ca6e777c36a4cfffe3f918b64a445c8f32300deeb9dfa5cc47261bd7b75d21 in /\"]}}"
}
],
"signatures": [
{
"header": {
"jwk": {
"crv": "P-256",
"kid": "FIFX:SJRD:AQHW:MCFX:M6WC:LXI2:3VO2:4LFW:UHDZ:QUN7:OLX4:6WGD",
"kty": "EC",
"x": "Xm8wJTzw3nb--rGoD3dxjKffikj7Snb9dHW-qGbqSAM",
"y": "GnATS--7lVcA_-jQGuDKTtjhmnGgvBrx8rLdlPOJV3U"
},
"alg": "ES256"
},
"signature": "f8NVzOF6ujm_0COedniGCGL_q3KsTfKFM9T8ZZDf2MSIMJ3TYoR_s795NqdEy8yWaoLuT2LoI0BCEsuOTZUhCw",
"protected": "eyJmb3JtYXRMZW5ndGgiOjE5MTQsImZvcm1hdFRhaWwiOiJDbjAiLCJ0aW1lIjoiMjAxNi0wNi0xMVQwMToxMzoyMVoifQ"
}
]
bash$ curl -I http://localhost:5000/v2/busybox/manifests/latest
HTTP/1.1 200 OK
Content-Length: 2561
Content-Type: application/vnd.docker.distribution.manifest.v1+prettyjws
Docker-Content-Digest: sha256:e45f25b1760f616e65f106b424f4ef29185fbd80822255d79dabc73b8eb715ad
Docker-Distribution-Api-Version: registry/2.0
Etag: "sha256:e45f25b1760f616e65f106b424f4ef29185fbd80822255d79dabc73b8eb715ad"
X-Content-Type-Options: nosniff
Date: Sat, 11 Jun 2016 01:21:26 GMT
No where in any of those API calls could I find the desired 47bcc53... image id that I see locally.
bash$ docker inspect busybox:latest
[
{
"Id": "sha256:47bcc53f74dc94b1920f0b34f6036096526296767650f223433fe65c35f149eb",
"RepoTags": [
"busybox:latest",
"localhost:5000/busybox:latest"
],
...
From this image spec the image id is a reproducible hash, and I do see the same value for the image id on different systems.
ImageID Each image's ID is given by the SHA256 hash of its configuration JSON. It is represented as a hexadecimal encoding of 256 bits, e.g., sha256:a9561eb1b190625c9adb5a9513e72c4dedafc1cb2d4c5236c9a6957ec7dfd5a9. Since the configuration JSON that gets hashed references hashes of each layer in the image, this formulation of the ImageID makes images content-addresable.
So if you can reproduce the configuration JSON from the API calls, then you may be able to generate the image id yourself.
From my research, you can obtain the image ID from the registry(2.3.0+) with
curl -H 'Accept: application/vnd.docker.distribution.manifest.v2+json' http://$server/v2/$repo/manifests/$tag
and the config.digest
field in the response represents imageID,that what you want!
refers: https://duyanghao.github.io/docker-registry-pull-manifest-v2/
You can get the image ID using the docker manifest
command:
docker manifest inspect <registry>/<name>:<tag>
The output will be JSON and the image ID is present at the path .config.digest
.
If you have jq
installed, you can run the following to print only the image ID:
docker manifest inspect <registry>/<name>:<tag> | jq -r '.config.digest | split(":")[1]'
© 2022 - 2024 — McMap. All rights reserved.