Most Docker users are aware that you can set labels when building images. You won’t find them in all images, but Bitnami images in particular make good use of them. For example:
$ docker image inspect --format='{{json .Config.Labels}}' bitnami/redis | jq
{
"org.opencontainers.image.base.name": "docker.io/bitnami/minideb:bullseye",
"org.opencontainers.image.created": "2023-06-14T15:37:46Z",
"org.opencontainers.image.description": "Application packaged by VMware, Inc",
"org.opencontainers.image.licenses": "Apache-2.0",
"org.opencontainers.image.ref.name": "7.0.11-debian-11-r20",
"org.opencontainers.image.title": "redis",
"org.opencontainers.image.vendor": "VMware, Inc.",
"org.opencontainers.image.version": "7.0.11"
}
Which tells us some useful information about what’s in the image and how it was built.
In this case, all the labels start with org.opencontainers.image
. These are standard metadata
names defined by OCI Image Format Specification.
One interesting thing is that the spec primarily talks about annotations rather than labels, and the two aren’t quite the same thing. To understand the difference we need to look into the specification. The image spec defines multiple files, but for our purposes we are most interested in these three:
- OCI Image Index A “higher level” file that points to lower level manifests. This is normally used to group platform specific images.
- OCI Image Manifest Defines the layers that make up a specific image and provides some metadata.
- OCI Image Configuration Defines various configuration for the image, including any volumes, the entrypoint and the default user.
Labels are set in the OCI Image Configuration. The documentation refers to this field as a label, but also says it “MUST use the annotation rules”.
Annotations can be set in multiple files, but the most relevant ones are the Image Index and Manifest.
I’m not aware of too many images that actually use annotations (as opposed to labels), but the Chainguard ones do:
$ docker manifest inspect cgr.dev/chainguard/wolfi-base@sha256:4cd09ab291469272c8cce1c187c09331dd33bbabd2dd7469587e48784c5e5641
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"size": 517,
"digest": "sha256:158eb22ec54653bdafba40d7caf1990f9ed8d69e0c6c44a841d4ce34539ea9d4"
},
"layers": [
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"size": 5614731,
"digest": "sha256:803940c3dee0594139d8bfaf580798931ac682003767b0a7f78ec07191357a96"
}
],
"annotations": {
"org.opencontainers.image.authors": "Chainguard Team https://www.chainguard.dev/",
"org.opencontainers.image.source": "https://github.com/chainguard-images/images/tree/main/images/wolfi-base",
"org.opencontainers.image.url": "https://edu.chainguard.dev/chainguard/chainguard-images/reference/wolfi-base/"
}
}
Notice I had to give the digest for the image in order to target a platform specific image and get the manifest as opposed to the index, which points to the platform specific images e.g:
$ docker manifest inspect cgr.dev/chainguard/wolfi-base
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.index.v1+json",
"manifests": [
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"size": 721,
"digest": "sha256:4cd09ab291469272c8cce1c187c09331dd33bbabd2dd7469587e48784c5e5641",
"platform": {
"architecture": "amd64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"size": 721,
"digest": "sha256:69d86becbee162a94e3b9a03d2132349a32d62a4887d71319eddf2ec084557e1",
"platform": {
"architecture": "arm64",
"os": "linux"
}
}
]
}
It is possible to set annotations on the index. At the time of writing, Chainguard Images don’t have annotations on the index, but a PR was recently merged to Apko that will set annotations both on the index and as Labels in the config. This should make it’s way into the Chainguard Images build workflow in the near future. If you want to stick to Docker, buildctl also has support for setting annotations (thanks to Brandon Mitchell for pointing me at this).
It’s also possible to use the crane tool to get labels or annotations from remote images. Crane also supprts supplying a specific platform, so we don’t need to use the digest:
$ crane manifest --platform linux/arm64 cgr.dev/chainguard/wolfi-base | jq '.annotations'
{
"org.opencontainers.image.authors": "Chainguard Team https://www.chainguard.dev/",
"org.opencontainers.image.source": "https://github.com/chainguard-images/images/tree/main/images/wolfi-base",
"org.opencontainers.image.url": "https://edu.chainguard.dev/chainguard/chainguard-images/reference/wolfi-base/"
}
Or:
$ crane config bitnami/redis | jq '.config.Labels'
{
"org.opencontainers.image.base.name": "docker.io/bitnami/minideb:bullseye",
"org.opencontainers.image.created": "2023-06-14T15:37:46Z",
"org.opencontainers.image.description": "Application packaged by VMware, Inc",
"org.opencontainers.image.licenses": "Apache-2.0",
"org.opencontainers.image.ref.name": "7.0.11-debian-11-r20",
"org.opencontainers.image.title": "redis",
"org.opencontainers.image.vendor": "VMware, Inc.",
"org.opencontainers.image.version": "7.0.11"
}
So what’s my point? Well, I don’t know really. It’s an interesting bit of container arcana. But I would like to see much better and more widespread usage of metadata, whether it’s annotations or labels. This metadata can be downloaded separately from the image and indexed in databases etc, so it’s easy to imagine sorting images by license, vendor etc without pulling the images themselves. If you’d like to read a bit more on use cases, take a look at Eric Smalling’s article How and when to use Docker labels / OCI container annotations. Just know that labels and annotations aren’t quite the same thing…