Stating the documentation the Docker image Id is computed as sha256 checksum of the image config json.
For example, for the classic hello-world image I can see the following image id
» docker images --no-trunc
reg.ngrok.io/library/hello-world latest sha256:feb5d9fea6a5e9606aa995e879d862b825965ba48de054caab5ef356dc6b3412 4 months ago 13.3kB
However, in the image tar I can see the following image config json content
{
"architecture":"amd64",
"config":{
"Hostname":"",
"Domainname":"",
"User":"",
"AttachStdin":false,
"AttachStdout":false,
"AttachStderr":false,
"Tty":false,
"OpenStdin":false,
"StdinOnce":false,
"Env":[
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd":[
"/hello"
],
"Image":"sha256:b9935d4e8431fb1a7f0989304ec86b3329a99a25f5efdc7f09f3f8c41434ca6d",
"Volumes":null,
"WorkingDir":"",
"Entrypoint":null,
"OnBuild":null,
"Labels":null
},
"container":"8746661ca3c2f215da94e6d3f7dfdcafaff5ec0b21c9aff6af3dc379a82fbc72",
"container_config":{
"Hostname":"8746661ca3c2",
"Domainname":"",
"User":"",
"AttachStdin":false,
"AttachStdout":false,
"AttachStderr":false,
"Tty":false,
"OpenStdin":false,
"StdinOnce":false,
"Env":[
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd":[
"/bin/sh",
"-c",
"#(nop) ",
"CMD [\"/hello\"]"
],
"Image":"sha256:b9935d4e8431fb1a7f0989304ec86b3329a99a25f5efdc7f09f3f8c41434ca6d",
"Volumes":null,
"WorkingDir":"",
"Entrypoint":null,
"OnBuild":null,
"Labels":{
}
},
"created":"2021-09-23T23:47:57.442225064Z",
"docker_version":"20.10.7",
"history":[
{
"created":"2021-09-23T23:47:57.098990892Z",
"created_by":"/bin/sh -c #(nop) COPY file:50563a97010fd7ce1ceebd1fa4f4891ac3decdf428333fb2683696f4358af6c2 in / "
},
{
"created":"2021-09-23T23:47:57.442225064Z",
"created_by":"/bin/sh -c #(nop) CMD [\"/hello\"]",
"empty_layer":true
}
],
"os":"linux",
"rootfs":{
"type":"layers",
"diff_ids":[
"sha256:e07ee1baac5fae6a26f30cabfe54a36d3402f96afda318fe0a96cec4ca393359"
]
}
}
The above document contains the following attributes that do not match with the expected image id:
"Image":"sha256:b9935d4e8431fb1a7f0989304ec86b3329a99a25f5efdc7f09f3f8c41434ca6d"
"container":"8746661ca3c2f215da94e6d3f7dfdcafaff5ec0b21c9aff6af3dc379a82fbc72",
How those attributes are computed? could not find any documentation at this regard.
CodePudding user response:
The config.Image, container, and container_config can all be ignored, you won't even see those fields when you build with other tools like buildkit. They come from how the classic builder creates images by creating dangling images for each build step, and this shows some of id's and randomly generated numbers associated with those previous steps.
Since I don't have your image, I'm going to work through an example with busybox cloned to my local registry:
$ docker image ls --no-trunc localhost:5000/library/busybox
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost:5000/library/busybox inspect sha256:beae173ccac6ad749f76713cf4440fe3d21d1043fe616dfbe30775815d1d0f6a 4 weeks ago 1.24MB
localhost:5000/library/busybox latest sha256:beae173ccac6ad749f76713cf4440fe3d21d1043fe616dfbe30775815d1d0f6a 4 weeks ago 1.24MB
localhost:5000/library/busybox <none> sha256:cabb9f684f8ba3edb303d578bfd7d709d853539ea1b420a3f6c81a08e85bb3d7 3 months ago 1.24MB
The ID I'm looking for is sha256:beae173ccac6ad749f76713cf4440fe3d21d1043fe616dfbe30775815d1d0f6a. And I see that in the image inspect:
$ docker inspect localhost:5000/library/busybox
[
{
"Id": "sha256:beae173ccac6ad749f76713cf4440fe3d21d1043fe616dfbe30775815d1d0f6a",
"RepoTags": [
"busybox:latest",
"localhost:5000/library/busybox:inspect",
"localhost:5000/library/busybox:latest"
],
"RepoDigests": [
"busybox@sha256:5acba83a746c7608ed544dc1533b87c737a0b0fb730301639a0179f9344b1678",
"localhost:5000/library/busybox@sha256:5acba83a746c7608ed544dc1533b87c737a0b0fb730301639a0179f9344b1678",
"localhost:5000/library/busybox@sha256:62ffc2ed7554e4c6d360bce40bbcf196573dd27c4ce080641a2c59867e732dee"
],
"Parent": "",
"Comment": "",
"Created": "2021-12-30T19:19:41.006954958Z",
"Container": "a0007fa726185ffbcb68e90f8edabedd79a08949f32f4f0bcc6e5fed713a72c8",
"ContainerConfig": {
"Hostname": "a0007fa72618",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"CMD [\"sh\"]"
],
"Image": "sha256:da658412c37aa24e561eb7e16c61bc82a9711340d8fb5cf1a8f39d8e96d7f723",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {}
},
"DockerVersion": "20.10.7",
"Author": "",
"Config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"sh"
],
"Image": "sha256:da658412c37aa24e561eb7e16c61bc82a9711340d8fb5cf1a8f39d8e96d7f723",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": null
},
"Architecture": "amd64",
"Os": "linux",
"Size": 1239820,
"VirtualSize": 1239820,
"GraphDriver": {
"Data": {
"MergedDir": "/home/docker/overlay2/558763c3b913289624792cf7f43a9b22a30f65eaab714b26d7da2a977070070a/merged",
"UpperDir": "/home/docker/overlay2/558763c3b913289624792cf7f43a9b22a30f65eaab714b26d7da2a977070070a/diff",
"WorkDir": "/home/docker/overlay2/558763c3b913289624792cf7f43a9b22a30f65eaab714b26d7da2a977070070a/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:01fd6df81c8ec7dd24bbbd72342671f41813f992999a3471b9d9cbc44ad88374"
]
},
"Metadata": {
"LastTagTime": "2022-01-30T19:48:56.850389545-05:00"
}
}
]
For computing the config digest, I'm going to look at the image as it is on the registry. The config should look the same there:
$ regctl image inspect localhost:5000/library/busybox --format raw-body | jq .
{
"architecture": "amd64",
"config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"sh"
],
"Image": "sha256:da658412c37aa24e561eb7e16c61bc82a9711340d8fb5cf1a8f39d8e96d7f723",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": null
},
"container": "a0007fa726185ffbcb68e90f8edabedd79a08949f32f4f0bcc6e5fed713a72c8",
"container_config": {
"Hostname": "a0007fa72618",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"CMD [\"sh\"]"
],
"Image": "sha256:da658412c37aa24e561eb7e16c61bc82a9711340d8fb5cf1a8f39d8e96d7f723",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {}
},
"created": "2021-12-30T19:19:41.006954958Z",
"docker_version": "20.10.7",
"history": [
{
"created": "2021-12-30T19:19:40.833034683Z",
"created_by": "/bin/sh -c #(nop) ADD file:6db446a57cbd2b7f4cfde1f280177b458390ed5a6d1b54c6169522bc2c4d838e in / "
},
{
"created": "2021-12-30T19:19:41.006954958Z",
"created_by": "/bin/sh -c #(nop) CMD [\"sh\"]",
"empty_layer": true
}
],
"os": "linux",
"rootfs": {
"type": "layers",
"diff_ids": [
"sha256:01fd6df81c8ec7dd24bbbd72342671f41813f992999a3471b9d9cbc44ad88374"
]
}
}
And running that original config (without jq formatting) through a sha256sum, you see the desired "image id" value:
$ regctl image inspect localhost:5000/library/busybox --format raw-body | sha256sum
beae173ccac6ad749f76713cf4440fe3d21d1043fe616dfbe30775815d1d0f6a -
This same digest is visible in the image manifest. Images are made up of content addressable storage, so the digest of each of the components is calculated and pushed to the registry before the manifest is pushed:
$ regctl image manifest localhost:5000/library/busybox
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2 json",
"config": {
"mediaType": "application/vnd.docker.container.image.v1 json",
"size": 1456,
"digest": "sha256:beae173ccac6ad749f76713cf4440fe3d21d1043fe616dfbe30775815d1d0f6a"
},
"layers": [
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 772788,
"digest": "sha256:5cc84ad355aaa64f46ea9c7bbcc319a9d808ab15088a27209c9e70ef86e5a2aa"
}
]
}
That manifest itself has a digest, which you can compute by calculating the sha256sum on itself, and you'll see the same digest in the manifest list of multi-platform images:
$ regctl image manifest localhost:5000/library/busybox --format raw-body | sha256sum
62ffc2ed7554e4c6d360bce40bbcf196573dd27c4ce080641a2c59867e732dee -
$ regctl image manifest --list localhost:5000/library/busybox --format '{{ jsonPretty . }}'
{
"manifests": [
{
"digest": "sha256:62ffc2ed7554e4c6d360bce40bbcf196573dd27c4ce080641a2c59867e732dee",
"mediaType": "application\/vnd.docker.distribution.manifest.v2 json",
"platform": {
"architecture": "amd64",
"os": "linux"
},
"size": 527
},
{
"digest": "sha256:ca038f83e1a3a6a08b539830ca3beefb503a3989cc1f19c265ae4e624a45a9cc",
"mediaType": "application\/vnd.docker.distribution.manifest.v2 json",
"platform": {
"architecture": "arm",
"os": "linux",
"variant": "v5"
},
"size": 527
},
{
"digest": "sha256:b27cc98025245c0e746b201d5c773faff99869ae58585090182e18d7c5e8a5e2",
"mediaType": "application\/vnd.docker.distribution.manifest.v2 json",
"platform": {
"architecture": "arm",
"os": "linux",
"variant": "v6"
},
"size": 527
},
{
"digest": "sha256:4ca297c4a8fdaf9806239ddcaf7c91266614c15d2c50b1acc96c0401ed18e544",
"mediaType": "application\/vnd.docker.distribution.manifest.v2 json",
"platform": {
"architecture": "arm",
"os": "linux",
"variant": "v7"
},
"size": 527
},
{
"digest": "sha256:a77fe109c026308f149d36484d795b42efe0fd29b332be9071f63e1634c36ac9",
"mediaType": "application\/vnd.docker.distribution.manifest.v2 json",
"platform": {
"architecture": "arm64",
"os": "linux",
"variant": "v8"
},
"size": 527
},
{
"digest": "sha256:839f94220ea4ab84e1b6364f7c3f311085a51904d4f5d76d022aead017fe2e1a",
"mediaType": "application\/vnd.docker.distribution.manifest.v2 json",
"platform": {
"architecture": "386",
"os": "linux"
},
"size": 527
},
{
"digest": "sha256:04b9b3684bf435766a3ec5f31f7db0b27ace0c13f4f9d514724432e96b0e7ccd",
"mediaType": "application\/vnd.docker.distribution.manifest.v2 json",
"platform": {
"architecture": "mips64le",
"os": "linux"
},
"size": 527
},
{
"digest": "sha256:d70e38f76482b3e5b1be06dbfe7aaf9cac00bb00678931b6e14785bee41caf3d",
"mediaType": "application\/vnd.docker.distribution.manifest.v2 json",
"platform": {
"architecture": "ppc64le",
"os": "linux"
},
"size": 528
},
{
"digest": "sha256:22b3bb958147afeb0db0122c91cb7d8b3a9d691b0d4e532e0cf79078cc80916f",
"mediaType": "application\/vnd.docker.distribution.manifest.v2 json",
"platform": {
"architecture": "riscv64",
"os": "linux"
},
"size": 527
},
{
"digest": "sha256:6b52cb58f1bfdd3b6068cc91febb82668f2ee16939e926fa67bab898863b6139",
"mediaType": "application\/vnd.docker.distribution.manifest.v2 json",
"platform": {
"architecture": "s390x",
"os": "linux"
},
"size": 528
}
],
"mediaType": "application\/vnd.docker.distribution.manifest.list.v2 json",
"schemaVersion": 2
}
And even that multi-platform manifest has a digest, where both this and the platform specific digest appear in the RepoDigests in the image inspect:
$ regctl image manifest --list localhost:5000/library/busybox --format raw-body | sha256sum
5acba83a746c7608ed544dc1533b87c737a0b0fb730301639a0179f9344b1678 -
Note the regctl command here is my own, from regclient and similar tools can be found from Google's crane and RedHat's skopeo.
For more details on the image specification, I'd recommend looking at the OCI image spec.
