Reputation: 69
For example I have an Alpine
image pulled from Dockerhub. Just by using docker pull alpine
. It was tagged with current date (let say 2019-12-12).
So now I want to update the image but first I want to check the last updated date for the latest
or newest version before pulling it.
For local image we can just use docker inspect alpine:latest
. Is there any API or command that can get that done?
Upvotes: 6
Views: 13269
Reputation: 9057
With the v2 manifest format this can now be accomplished with:
docker manifest inspect -v <image>
This will show details on each layer of the remote Docker image, without pulling the image itself. This works with both Docker Hub and private registries.
The output is a JSON array of objects, describing layer digests, sizes, platforms, etc.. Tools like jq can help to process this data on the command-line.
Example output:
> docker manifest inspect -v ubuntu:22.04
[
{
"Ref": "docker.io/library/ubuntu:22.04@sha256:2af372c1e2645779643284c7dc38775e3dbbc417b2d784a27c5a9eb784014fb8",
"Descriptor": {
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:2af372c1e2645779643284c7dc38775e3dbbc417b2d784a27c5a9eb784014fb8",
"size": 424,
"platform": {
"architecture": "amd64",
"os": "linux"
}
},
"Raw": "eyJzY2hlbWFWZXJzaW9uIjogMiwgIm1lZGlhVHlwZSI6ICJhcHBsaWNhdGlvbi92bmQub2NpLmltYWdlLm1hbmlmZXN0LnYxK2pzb24iLCAiY29uZmlnIjogeyJtZWRpYVR5cGUiOiAiYXBwbGljYXRpb24vdm5kLm9jaS5pbWFnZS5jb25maWcudjEranNvbiIsICJzaXplIjogMjI5NiwgImRpZ2VzdCI6ICJzaGEyNTY6NTI4ODI3NjFhNzJhNjA2NDllZGZmOWEyNDc4ODM1MzI1ZDA4NGZiNjQwZWEzMmE5NzVlMjllMTJhMDEyMDI1ZiJ9LCAibGF5ZXJzIjogW3sibWVkaWFUeXBlIjogImFwcGxpY2F0aW9uL3ZuZC5vY2kuaW1hZ2UubGF5ZXIudjEudGFyK2d6aXAiLCAic2l6ZSI6IDI5NTMzOTQ5LCAiZGlnZXN0IjogInNoYTI1NjphOGIxYzVmODBjMmQyYTc1N2FkYzk2M2UzZmUyZGFkMGI0ZDIyOWY4M2RmMzM0OWZiYjcwZTRkMTJkZDQ4ODIyIn1dfQ==",
"OCIManifest": {
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"size": 2296,
"digest": "sha256:52882761a72a60649edff9a2478835325d084fb640ea32a975e29e12a012025f"
},
"layers": [
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"size": 29533949,
"digest": "sha256:a8b1c5f80c2d2a757adc963e3fe2dad0b4d229f83df3349fbb70e4d12dd48822"
}
]
}
},
{
"Ref": "docker.io/library/ubuntu:22.04@sha256:2f63021dc56651000aa1e250d42c3aa898a5cd61120aeb8daf9e7e0fd20b84e5",
"Descriptor": {
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:2f63021dc56651000aa1e250d42c3aa898a5cd61120aeb8daf9e7e0fd20b84e5",
"size": 424,
"platform": {
"architecture": "arm",
"os": "linux",
"variant": "v7"
}
},
"Raw": "eyJzY2hlbWFWZXJzaW9uIjogMiwgIm1lZGlhVHlwZSI6ICJhcHBsaWNhdGlvbi92bmQub2NpLmltYWdlLm1hbmlmZXN0LnYxK2pzb24iLCAiY29uZmlnIjogeyJtZWRpYVR5cGUiOiAiYXBwbGljYXRpb24vdm5kLm9jaS5pbWFnZS5jb25maWcudjEranNvbiIsICJzaXplIjogMjMxMiwgImRpZ2VzdCI6ICJzaGEyNTY6YTA1MTRmNjgyMmYzODFkN2EyNDBkZmU4YzQxOTU4MjE2NGFmNWFkOTQ2NWMxYTk1YjY5ZDFiNDRkYWVkYWJkYiJ9LCAibGF5ZXJzIjogW3sibWVkaWFUeXBlIjogImFwcGxpY2F0aW9uL3ZuZC5vY2kuaW1hZ2UubGF5ZXIudjEudGFyK2d6aXAiLCAic2l6ZSI6IDI2NjM5Nzg5LCAiZGlnZXN0IjogInNoYTI1NjpmNWI0MjEzODI0ZmMzNTE1YjY4ZTY4NDRkM2ZjMjg5YWUwMGVmOGNkMDdkZGNkNDM4NTZjM2FkN2ZhZWExNmQ0In1dfQ==",
"OCIManifest": {
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"size": 2312,
"digest": "sha256:a0514f6822f381d7a240dfe8c419582164af5ad9465c1a95b69d1b44daedabdb"
},
"layers": [
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"size": 26639789,
"digest": "sha256:f5b4213824fc3515b68e6844d3fc289ae00ef8cd07ddcd43856c3ad7faea16d4"
}
]
}
},
{
"Ref": "docker.io/library/ubuntu:22.04@sha256:462e829de9164b6c066246cddc265a936071744f689f0ea73daa92b4f9feb47e",
"Descriptor": {
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:462e829de9164b6c066246cddc265a936071744f689f0ea73daa92b4f9feb47e",
"size": 424,
"platform": {
"architecture": "arm64",
"os": "linux",
"variant": "v8"
}
},
"Raw": "eyJzY2hlbWFWZXJzaW9uIjogMiwgIm1lZGlhVHlwZSI6ICJhcHBsaWNhdGlvbi92bmQub2NpLmltYWdlLm1hbmlmZXN0LnYxK2pzb24iLCAiY29uZmlnIjogeyJtZWRpYVR5cGUiOiAiYXBwbGljYXRpb24vdm5kLm9jaS5pbWFnZS5jb25maWcudjEranNvbiIsICJzaXplIjogMjMxNCwgImRpZ2VzdCI6ICJzaGEyNTY6NzQyMzM1N2VkNjA5ZjEzYmE5MDMxM2Y0MzQ1NGRjMzAyNmFmYjI2NDc2ZTE0Y2I4YjFkYmIzZWFkYjhhMTkyYyJ9LCAibGF5ZXJzIjogW3sibWVkaWFUeXBlIjogImFwcGxpY2F0aW9uL3ZuZC5vY2kuaW1hZ2UubGF5ZXIudjEudGFyK2d6aXAiLCAic2l6ZSI6IDI3MzYwNTMwLCAiZGlnZXN0IjogInNoYTI1NjpkNWEyYWQ3MjljMDlmYmZkYjI1OWFlNzY0ZjkyMTg4ZWZjNjdhNjE1ZmZkZTliYjM0YTQ2Mjk4ZDFlZGYzY2Q2In1dfQ==",
"OCIManifest": {
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"size": 2314,
"digest": "sha256:7423357ed609f13ba90313f43454dc3026afb26476e14cb8b1dbb3eadb8a192c"
},
"layers": [
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"size": 27360530,
"digest": "sha256:d5a2ad729c09fbfdb259ae764f92188efc67a615ffde9bb34a46298d1edf3cd6"
}
]
}
},
{
"Ref": "docker.io/library/ubuntu:22.04@sha256:6250b8edd7248ca0764e8c10069113ac1c837becd6e1e5a92991dfa14dce842f",
"Descriptor": {
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:6250b8edd7248ca0764e8c10069113ac1c837becd6e1e5a92991dfa14dce842f",
"size": 424,
"platform": {
"architecture": "ppc64le",
"os": "linux"
}
},
"Raw": "eyJzY2hlbWFWZXJzaW9uIjogMiwgIm1lZGlhVHlwZSI6ICJhcHBsaWNhdGlvbi92bmQub2NpLmltYWdlLm1hbmlmZXN0LnYxK2pzb24iLCAiY29uZmlnIjogeyJtZWRpYVR5cGUiOiAiYXBwbGljYXRpb24vdm5kLm9jaS5pbWFnZS5jb25maWcudjEranNvbiIsICJzaXplIjogMjI5OSwgImRpZ2VzdCI6ICJzaGEyNTY6YWY1NmRkNGRhYWY0ZmZlODg4OTFkMzg2YzQwMzJkMTkwMzQ1MTI3YTczNTE5ZWRiY2UxZTgwNGY3YjgxYzllYyJ9LCAibGF5ZXJzIjogW3sibWVkaWFUeXBlIjogImFwcGxpY2F0aW9uL3ZuZC5vY2kuaW1hZ2UubGF5ZXIudjEudGFyK2d6aXAiLCAic2l6ZSI6IDM0NDYxMjIzLCAiZGlnZXN0IjogInNoYTI1Njo1YjdjZjk0MjkxZWExNjhjY2RjMjAzOTY1YTc5ZjU0NjAzYTRmZTJlMDczOGEzYWNmMGY3YThkODYwZTUxZjMyIn1dfQ==",
"OCIManifest": {
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"size": 2299,
"digest": "sha256:af56dd4daaf4ffe88891d386c4032d190345127a73519edbce1e804f7b81c9ec"
},
"layers": [
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"size": 34461223,
"digest": "sha256:5b7cf94291ea168ccdc203965a79f54603a4fe2e0738a3acf0f7a8d860e51f32"
}
]
}
},
{
"Ref": "docker.io/library/ubuntu:22.04@sha256:4b24be9d94475438fe8313d8772be9c94e7c89d4e2b2d2a7570dcb3a7f51ee80",
"Descriptor": {
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:4b24be9d94475438fe8313d8772be9c94e7c89d4e2b2d2a7570dcb3a7f51ee80",
"size": 424,
"platform": {
"architecture": "s390x",
"os": "linux"
}
},
"Raw": "eyJzY2hlbWFWZXJzaW9uIjogMiwgIm1lZGlhVHlwZSI6ICJhcHBsaWNhdGlvbi92bmQub2NpLmltYWdlLm1hbmlmZXN0LnYxK2pzb24iLCAiY29uZmlnIjogeyJtZWRpYVR5cGUiOiAiYXBwbGljYXRpb24vdm5kLm9jaS5pbWFnZS5jb25maWcudjEranNvbiIsICJzaXplIjogMjI5NywgImRpZ2VzdCI6ICJzaGEyNTY6N2ViMzNkNGNmODQxOGU0ZTFjOTc0ODk5NzljOTYzMTVmNjc3MTMyN2M4ZjgyYjRiZjYwMmU0NTM4N2E0MzBmYSJ9LCAibGF5ZXJzIjogW3sibWVkaWFUeXBlIjogImFwcGxpY2F0aW9uL3ZuZC5vY2kuaW1hZ2UubGF5ZXIudjEudGFyK2d6aXAiLCAic2l6ZSI6IDI4MDAwNDIzLCAiZGlnZXN0IjogInNoYTI1NjowMWM3ZmNjYTVmZDkzMDEwOGQ0NjlhZWI5ZDg2MjQ5ZWI3ZjJjZGM3NTY5OWRmYThkZDEzMmQ5YjVmNTVkMjlmIn1dfQ==",
"OCIManifest": {
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"size": 2297,
"digest": "sha256:7eb33d4cf8418e4e1c97489979c96315f6771327c8f82b4bf602e45387a430fa"
},
"layers": [
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"size": 28000423,
"digest": "sha256:01c7fcca5fd930108d469aeb9d86249eb7f2cdc75699dfa8dd132d9b5f55d29f"
}
]
}
}
]
The "docker manifest" command is considered "experimental" and the API may change in future versions.
https://docs.docker.com/reference/cli/docker/manifest/inspect/
Upvotes: 8
Reputation: 263627
Like David says in the comments, a docker pull
will only pull changed layers.
$ docker pull alpine:latest
latest: Pulling from library/alpine
a0d0a0d46f8b: Already exists
Digest: sha256:e1c082e3d3c45cccac829840a25941e679c25d438cc8412c2fa221cf1a824e6a
Status: Downloaded newer image for alpine:latest
docker.io/library/alpine:latest
$ docker pull alpine:latest
latest: Pulling from library/alpine
Digest: sha256:e1c082e3d3c45cccac829840a25941e679c25d438cc8412c2fa221cf1a824e6a
Status: Image is up to date for alpine:latest
docker.io/library/alpine:latest
In fact, from the output, you can see it checking the digest of the manifest list, so I don't believe it's even pulling the manifest on the second query, it can check that with a simple head request. And as for why the first pull mentioned a0d0a0d46f8b: Already exists
, if another image based on that Alpine image had been pulled, the underlying layer would have already been retrieved.
If you do want to check data from the registry directly without pulling the image and layers, there are a variety of tools to do that. The ones I know of include RedHat's skopeo, Googles crane (part of go-containerregistry), and I've developed a regclient project that includes commands like regctl
:
$ regctl image digest --list alpine:latest
sha256:e1c082e3d3c45cccac829840a25941e679c25d438cc8412c2fa221cf1a824e6a
And you can compare that against what docker sees in the image:
$ docker image inspect alpine:latest --format '{{.RepoDigests}}'
[alpine@sha256:e1c082e3d3c45cccac829840a25941e679c25d438cc8412c2fa221cf1a824e6a]
It also allows you to check the image config without downloading the layers:
$ regctl image config alpine:latest
{
"created": "2021-08-27T17:19:45.758611523Z",
"architecture": "amd64",
"os": "linux",
"config": {
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh"
]
},
"rootfs": {
"type": "layers",
"diff_ids": [
"sha256:e2eb06d8af8218cfec8210147357a68b7e13f7c485b991c288c2d01dc228bb68"
]
},
"history": [
{
"created": "2021-08-27T17:19:45.553092363Z",
"created_by": "/bin/sh -c #(nop) ADD file:aad4290d27580cc1a094ffaf98c3ca2fc5d699fe695dfb8e6e9fac20f1129450 in / "
},
{
"created": "2021-08-27T17:19:45.758611523Z",
"created_by": "/bin/sh -c #(nop) CMD [\"/bin/sh\"]",
"empty_layer": true
}
]
}
Upvotes: 1