How come two docker images have the same image ID and same tag, but different digests?

Viewed 831

When I docker pull hello-world, I got the image with a digest of f9dfddf63636d84ef479d645ab5885156ae030f611a56f3a7ac7f2fdd86d7e4e

$ docker pull hello-world
Using default tag: latest
latest: Pulling from library/hello-world
Digest: sha256:f9dfddf63636d84ef479d645ab5885156ae030f611a56f3a7ac7f2fdd86d7e4e
Status: Image is up to date for hello-world:latest
docker.io/library/hello-world:latest

I was using a Mac, but when I docker inspect hello-world:latest, I saw the os/arch is linux/amd64

    ...
    "Architecture": "amd64",
    "Os": "linux",
    ...

So I went to https://hub.docker.com/_/hello-world/?tab=tags and found strangely enough, the latest hello-world for linux/amd64 is at https://hub.docker.com/layers/hello-world/library/hello-world/latest/images/sha256-92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a?context=explore with a digest of 92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a

So I pulled down this image as well

$ docker pull hello-world@sha256:92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a
sha256:92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a: Pulling from library/hello-world
Digest: sha256:92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a
Status: Downloaded newer image for hello-world@sha256:92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a
docker.io/library/hello-world@sha256:92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a

Surprisingly, I ended up with two images with the same tag, same image ID, but different digests.

$ docker image ls --digests
REPOSITORY                    TAG                 DIGEST                                                                    IMAGE ID            CREATED             SIZE
hello-world                   latest              sha256:92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a   fce289e99eb9        15 months ago       1.84kB
hello-world                   latest              sha256:f9dfddf63636d84ef479d645ab5885156ae030f611a56f3a7ac7f2fdd86d7e4e   fce289e99eb9        15 months ago       1.84kB

Are these two images the same one? How can I uniquely address an image if I want consistency across my team?

3 Answers

The hello-world image is a multi-platform image. Each platform contains its own manifest, and there is a manifest list that points to all of the platforms. Each of those manifests and the manifest list have their own digest. In your listing, docker is showing the digest for the manifest list, and your specific platform manifest's digest:

$ docker buildx imagetools inspect hello-world@sha256:f9dfddf63636d84ef479d645ab5885156ae030f611a56f3a7ac7f2fdd86d7e4e
Name:      docker.io/library/hello-world@sha256:f9dfddf63636d84ef479d645ab5885156ae030f611a56f3a7ac7f2fdd86d7e4e
MediaType: application/vnd.docker.distribution.manifest.list.v2+json
Digest:    sha256:f9dfddf63636d84ef479d645ab5885156ae030f611a56f3a7ac7f2fdd86d7e4e
           
Manifests: 
  Name:      docker.io/library/hello-world@sha256:92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/amd64
             
  Name:      docker.io/library/hello-world@sha256:e5785cb0c62cebbed4965129bae371f0589cadd6d84798fb58c2c5f9e237efd9
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm/v5
             
  Name:      docker.io/library/hello-world@sha256:50b8560ad574c779908da71f7ce370c0a2471c098d44d1c8f6b513c5a55eeeb1
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm/v7
             
  Name:      docker.io/library/hello-world@sha256:963612c5503f3f1674f315c67089dee577d8cc6afc18565e0b4183ae355fb343
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm64/v8
             
  Name:      docker.io/library/hello-world@sha256:85dc5fbe16214366748ebe9d7cc73bc42d61d19d61fe05f01e317d278c2287ed
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/386
             
  Name:      docker.io/library/hello-world@sha256:8aaea2a718a29334caeaf225716284ce29dc17418edba98dbe6dafea5afcda16
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/ppc64le
             
  Name:      docker.io/library/hello-world@sha256:577ad4331d4fac91807308da99ecc107dcc6b2254bc4c7166325fd01113bea2a
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/s390x
             
  Name:      docker.io/library/hello-world@sha256:468a2702c410d84e275ed28dd0f46353d57d5a17f177aa7c27c2921e9ef9cd0e
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  windows/amd64
  OSVersion: 10.0.17763.1098

-> This is how manifest works with docker. Config.digest file remains same for both images as they are pointing towards same configuration of layers.
->The digest used for docker pull represents the digest of image manifest which is stored in a registry. This digest is considered the root of a hash chain since the manifest itself contains the hash of the content which will be downloaded and imported into docker.
->See the schema 2 spec for a description of this manifest https://docs.docker.com/registry/spec/manifest-v2-2/. The image id used within docker can be found in this manifest as config.digest. This config represents the image configuration which will be used within docker.
->So you could say the manifest is the envelope and image is what is inside. The manifest digest will always be different than the image id BUT for any given manifest the same image id should always be produced.
->As it is a hash chain, we cannot guarantee that the manifest digest will always be the same for a given image id.
-> In most cases it should usually produce the same digest, we just cannot guarantee it but do a best effort. The possible difference in manifest digest is because we do not store gzipped blobs locally and exporting of layers may produce a different digest, even though the uncompressed content should remain the same.
->The image id itself verifies that uncompressed content is the same, this is what we mean when we say the image id is now a content addressable identifier.

So I'm no expert in Docker, I can't tell you why this happenned or if it becomes an issue, however I just discovered here how to clean it up: https://docs.docker.com/engine/reference/commandline/rmi/

You can delete the second image using image ID, then all is well. To get the image ID use the command:

docker image list

Then once you have the ID, use the command:

docker image rmi <image ID> <-f if there are multiple images with the same ID>

You may end up having to delete all of your images and building the image you intended to use, however it will allow you to be confident that you are pushing the intended build.

Related