Inspect an image from Dockerhub without pulling the image
Asked Answered
N

2

6

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?

Namara answered 7/9, 2021 at 8:42 Comment(2)
You can use Skopeo. It is able to inspect a remote image showing its properties including its layers, without requiring you to pull the image to the host. Check examplesUniversal
docker pull won't re-download any image layers you already have locally, so if you just docker pull alpine that will in effect check if there is a newer version and download it only if there is. Would that meet your needs?Shall
S
7

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/

Suter answered 24/4 at 21:30 Comment(0)
C
1

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
    }
  ]
}
Christman answered 7/9, 2021 at 12:21 Comment(2)
This explains a lot. Thanks. Bwt I'm new to docker. Is there a way to know which version is considered as latest for an image? I tried to pull elasticsearch image using docker pull elasticsearch but it says Using default tag: latest Error response from daemon: manifest for elasticsearch:latest not found: manifest unknown: manifest unknown Any idea?Namara
@MinhNg latest is just another tag on the registry, would have been better if they called it default. Not every repository pushes that tag, likely to force the user to pick a version. From regctl, you can list tags with regctl tag ls elasticsearch but the data isn't there from the registry to correlate multiple tags to the same image without lots of queries. Easiest for these is to check Hub directly: hub.docker.com/_/elasticsearchChristman

© 2022 - 2024 — McMap. All rights reserved.