About container image digests Stay organized with collections Save and categorize content based on your preferences.
This page describes image digests, including what image digests are, how tofind them, and how to enforce their use in Kubernetes clusters. This pageis intended for developers and operators who build and deploy containerimages.
Acontainer image digest uniquely and immutably identifies a container image. When you deploy images bydigest, you avoid the downsides of deploying byimage tags.
The commands on this page assume that you have access to a Linux or macOSshell environment with tools such as theGoogle Cloud CLI,Docker, cURL,jq,andpack already installed. Or, you can useCloud Shell,which has these toolspre-installed.
Container images and image tags
When working with container images, you need a way to refer to the images thatyou use.Image tags are a common way of referring to different revisions of an image. A commonapproach is to tag images with a version identifier at build time. For example,v1.0.1 could refer to a version that you call1.0.1.
Tags make image revisions easy to look up by human-readable strings. However,tags are mutable references, which means the image referenced by a tag canchange, as illustrated in the following diagram:
As the previous diagram shows, if you publish a new image using the same tag asan existing image, the tag stops pointing to the existing image and startspointing to your new image.
Disadvantages of image tags
Because tags are mutable, they have the following disadvantages when you usethem to deploy an image:
In Kubernetes, deploying by tag can result in unexpected results. Forexample, assume that you have an existing Deployment resource thatreferences a container image by tag
v1.0.1. To fix a bug or make a smallchange, your build process creates a new image with the same tagv1.0.1.New Pods that are created from your Deployment resource can end up usingeither the old or the new image, even if you don't change your Deploymentresource specification. This problem also applies to other Kubernetesresources such as StatefulSets, DaemonSets, ReplicaSets, and Jobs.If you use tools to scan or analyze images, results from these toolsare only valid for the image that was scanned. To ensure that you deploythe image that was scanned, you cannot rely on the tag because the imagereferred by the tag might have changed.
If you useBinary Authorization withGoogle Kubernetes Engine (GKE),tag-based deployment is disallowed because it's impossible to determine theexact image that is used when a Pod is created.
When you deploy your images, you can use an image digest to avoid thedisadvantages of using tags. You can still add tags to your images if you like,but you don't have to do so.
Structure of an image
An image consists of the following components:
- Animage manifest
- Aconfiguration object
- An array of one or morefile system layers
- An optionalimage index
These components are illustrated in the following diagram:
The preceding image shows additional detail about image components:
- The image manifest is a JSON document that contains a reference to theconfiguration object, the file system layers, and optional metadata.
- The image manifest references the configuration object and each of thefile system layers using their
digestattributes. The value of adigestattribute is a cryptographic hash of the contents that the digestrefers to, typically calculated using theSHA-256 algorithm. - The digest values are used to construct immutable addresses to theobjects. This process is calledcontent-addressable storage,and it means that you can retrieve image manifests, image indexes,configuration objects, and layers based on their digests.
- The image digest is the hash of the image index or image manifest JSONdocument.
- The configuration object is a JSON document that definesproperties of the image,such as the CPU architecture, entrypoint, exposed ports, and environmentvariables.
- The file system layer array defines the order that the container runtimeuses to stack the layers. The layers are distributed astar files,typically compressed using the
gziputility. - The optional image index, sometimes referred to as themanifest list,refers to one or more image manifests. The reference is the digest of theimage manifest. An image index is useful when you produce multiple relatedimages for differentplatforms,such as
amd64andarm64architectures.
For more information, see the sectionExploring image manifests, digests, and tags.
Finding image digests
To use image digests for deployment, you must first find the digest. Then, youcan use the digest with your deployment command or include it in your Kubernetesmanifests.
You can get the digest of an image in various ways, depending on your currentsituation. The following sections contain examples for different products andtools.
In the following sections, run the commands in Cloud Shell or in ashell environment with tools such as the gcloud CLI, Docker, cURL,andjq already installed.
Artifact Registry
For images stored inArtifact Registry,you can use the
gcloud artifacts docker images describecommand.gcloud artifacts docker images describe \LOCATION-docker.pkg.dev/PROJECT/REPOSITORY/IMAGE:TAG \ --format 'value(image_summary.digest)'
Replace the following:
LOCATION: the regional or multi-regionallocation of your repositoryPROJECT: yourGoogle Cloud project IDREPOSITORY: your repository nameIMAGE: your image nameTAG: your image tag
Container Registry
Caution: Container Registry is deprecated. Effective March 18, 2025, Container Registry is shut down, and writing images to Container Registry is unavailable. For details on the deprecation and how to migrate to Artifact Registry, seeContainer Registry deprecation.
For images stored inContainer Registry,you can use the
gcloud container images describecommand to get the digest for an image by providing the name and a tag. Use the--formatflag to only display the digest:gcloudcontainerimagesdescribe\gcr.io/google-containers/pause-amd64:3.2\--format'value(image_summary.digest)'The output looks similar to the following, though your digest value mightdiffer:
sha256:4a1c4b21597c1b4415bdbecb28a3296c6b5e23ca4f9feeb599860a1dac6a0108
Cloud Build
For images built usingCloud Build,you can get the image digest by using thegcloud builds describe command with the--format flag. This approach works regardless of which registryyou used to publish your image.
For an already completed build, do the following:
Get a list of builds for your project:
gcloudbuildslistMake a note of a
BUILD_ID.Get the image digest:
gcloud builds describeBUILD_ID \ --format 'value(results.images[0].digest)'
Replace
BUILD_IDwith the unique ID thatCloud Build assigned to your build.
Get the image name and digest for the latest build fromCloud Build for your current project:
gcloudbuildsdescribe\$(gcloudbuildslist--limit1--format'value(id)')\--format'value[separator="@"](results.images[0].name,results.images[0].digest)'If your build produced multiple images, filter the output and get thedigest of one of the images:
gcloud builds describeBUILD_ID --format json \ | jq -r '.results.images[] | select(.name=="YOUR_IMAGE_NAME") | .digest'
Replace
YOUR_IMAGE_NAMEwith the name of one of theimages from yourcloudbuild.yamlfile.If you submit a build to Cloud Build using the
gcloud builds submitcommand,you can capture the image digest from the output in an environment variable:IMAGE_DIGEST=$(gcloud builds submit \ --format 'value(results.images[0].digest)' | tail -n1)
Cloud Native Buildpacks
If you useCloud Native Buildpacks and the Google Cloud builder to build and publish images, you cancapture the image name and digest by using the
--quietflag with thepackcommand:pack build --builder gcr.io/buildpacks/builder:v1 --publish --quiet \LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE \ > image-with-digest.txt
Replace the following:
LOCATION: the regional or multi-regionallocation of your repositoryPROJECT_ID: yourGoogle Cloud project IDREPOSITORY: your repository nameIMAGE: your image name
The file
image-with-digest.txtcontains the image name and digest.Use the
--tagflag if you want to add tags to the image.
Docker client
The
manifestsubcommand of thedockercommand line client can fetch image manifests and manifest listsfrom container image registries.Get the digest from the manifest list of the image
registry.k8s.io/pause:3.9, for theamd64CPU architecture and thelinuxoperating system:dockermanifestinspect--verboseregistry.k8s.io/pause:3.9|\jq-r'iftype=="object"then.Descriptor.digestelse.[]|select(.Descriptor.platform.architecture=="amd64"and.Descriptor.platform.os=="linux")|.Descriptor.digestend'The output looks similar to the following:
sha256:8d4106c88ec0bd28001e34c975d65175d994072d65341f62a8ab0754b0fafe10For images that are stored in your localDocker daemon,and that have been either pulled from or pushed to an image registry,you can use the Docker command line tool to get the image digest:
Pull the image to your localDocker daemon:
dockerpulldocker.io/library/debian:bookwormGet the image digest:
dockerinspectdocker.io/library/debian:bookworm\|jq-r'.[0].RepoDigests[0]'\|cut-d'@'-f2The output looks similar to the following, though your digest valuemay differ:
sha256:3d868b5eb908155f3784317b3dda2941df87bbbbaa4608f84881de66d9bb297b
List all images and digests in your local Docker daemon:
docker images --digestsThe output shows digests for images that have a digest value. Images onlyhave a digest value if they were pulled from or pushed to an image registry.
crane andgcrane
You can use the open sourcecrane andgcrane command-line tools toget the digest of an image without pulling the image to a local Docker daemon.
Download
craneandgcraneto your current directory:VERSION=$(curl-sLhttps://api.github.com/repos/google/go-containerregistry/releases/latest|jq-r.tag_name)curl-L"https://github.com/google/go-containerregistry/releases/download/${VERSION}/go-containerregistry_$(uname -s)_$(uname -m).tar.gz"|tar-zxf-cranegcraneGet image digests:
./gcrane digest gcr.io/distroless/static-debian11:nonrootcraneandgcranehave other features that are outside the scopeof this page. For more information, see the documentation forcraneandgcrane.
Enforcing the use of image digests in Kubernetes deployments
If you want to enforce using digests for images that you deploy to yourKubernetes clusters, you can usePolicy Controller orOpen Policy Agent (OPA) Gatekeeper.Policy Controller is built from the OPA Gatekeeper open source project.
Policy Controller and OPA Gatekeeper both build on theOPA policy engine.Policy Controller and OPA Gatekeeper provide aKubernetes validating admission webhook to enforce policies, andcustom resource definitions (CRDs) forconstraint templates andconstraints.
Constraint templates contain policy logic that is expressed using a high-leveldeclarative language calledRego.The following is a constraint template that validates that containers,init containers,andephemeral containers in a Kubernetes resource specification use images with digests:
apiVersion:templates.gatekeeper.sh/v1kind:ConstraintTemplatemetadata:name:k8simagedigestsannotations:metadata.gatekeeper.sh/title:"ImageDigests"metadata.gatekeeper.sh/version:1.0.1description:>-Requires container images to contain a digest.https://kubernetes.io/docs/concepts/containers/images/spec:crd:spec:names:kind:K8sImageDigestsvalidation:openAPIV3Schema:type:objectdescription:>-Requires container images to contain a digest.https://kubernetes.io/docs/concepts/containers/images/properties:exemptImages:description:>-Any container that uses an image that matches an entry in this list will be excludedfrom enforcement. Prefix-matching can be signified with `*`. For example:`my-image-*`.It is recommended that users use the fully-qualified Docker image name (e.g. start with a domain name)in order to avoid unexpectedly exempting images from an untrusted repository.type:arrayitems:type:stringtargets:-target:admission.k8s.gatekeeper.shrego:|package k8simagedigestsimport data.lib.exempt_container.is_exemptviolation[{"msg": msg}] {container := input.review.object.spec.containers[_]not is_exempt(container)not regex.match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image)msg := sprintf("container <%v> uses an image without a digest <%v>", [container.name, container.image])}violation[{"msg": msg}] {container := input.review.object.spec.initContainers[_]not is_exempt(container)not regex.match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image)msg := sprintf("initContainer <%v> uses an image without a digest <%v>", [container.name, container.image])}violation[{"msg": msg}] {container := input.review.object.spec.ephemeralContainers[_]not is_exempt(container)not regex.match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image)msg := sprintf("ephemeralContainer <%v> uses an image without a digest <%v>", [container.name, container.image])}libs:-|package lib.exempt_containeris_exempt(container) {exempt_images := object.get(object.get(input, "parameters", {}), "exemptImages", [])img := container.imageexemption := exempt_images[_]_matches_exemption(img, exemption)}_matches_exemption(img, exemption) {not endswith(exemption, "*")exemption == img}_matches_exemption(img, exemption) {endswith(exemption, "*")prefix := trim_suffix(exemption, "*")startswith(img, prefix)}The preceding policy contains a regular expression as input to there_match function.This regular expression matches the container image digest, and it is based onthedigest format in the Open Container Initiative Image Specification.
Constraints apply the policy to Kubernetes resources by matching againstattributes such askind andnamespace. The following example constraintapplies the policy from the constraint template to allPod resources in thedefault namespace.
apiVersion:constraints.gatekeeper.sh/v1beta1kind:K8sImageDigestsmetadata:name:container-image-must-have-digestspec:match:kinds:-apiGroups:[""]kinds:["Pod"]namespaces:-"default"After you create the constraint template and the constraint, any new pods inthedefault namespace must use image digests to reference container images.
For the full example, see theimagedigests policy in the Gatekeeper policy library.
About image manifests, digests, and tags
In this section, you learn how to explore existing images in registries usingcommand-linetools such ascurl anddocker. Run the commands in Cloud Shell orin a shell environment with tools such as the gcloud CLI, Docker,cURL, andjq already installed. The following commands use public images inArtifact Registry.
Get the manifest of the image
gcr.io/google-containers/pause-amd64:3.2by using cURL and themanifest URL:curl -s https://gcr.io/v2/google-containers/pause-amd64/manifests/3.2The output is similar to the following:
{ "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "config": { "mediaType": "application/vnd.docker.container.image.v1+json", "size": 759, "digest": "sha256:80d28bedfe5dec59da9ebf8e6260224ac9008ab5c11dbbe16ee3ba3e4439ac2c" }, "layers": [ { "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", "size": 296534, "digest": "sha256:c74f8866df097496217c9f15efe8f8d3db05d19d678a02d01cc7eaed520bb136" } ]}The
configsection has a digest attribute, and you can use this valueto retrieve the configuration object. Similarly, each layer has adigestattribute that you can use to retrieve the tar file for that layer.If the image includes the optional image index, an HTTP
GETrequestto the manifest URL using a tag returns the image index instead of theimage manifest.Get the image index of the image
gcr.io/google-containers/pause:3.2:curl -s https://gcr.io/v2/google-containers/pause/manifests/3.2The output is similar to the following:
{ "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json", "manifests": [ { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 526, "digest": "sha256:4a1c4b21597c1b4415bdbecb28a3296c6b5e23ca4f9feeb599860a1dac6a0108", "platform": { "architecture": "amd64", "os": "linux" } }, { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 526, "digest": "sha256:bbb7780ca6592cfc98e601f2a5e94bbf748a232f9116518643905aa30fc01642", "platform": { "architecture": "arm", "os": "linux", "variant": "v7" } }, { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 526, "digest": "sha256:31d3efd12022ffeffb3146bc10ae8beb890c80ed2f07363515580add7ed47636", "platform": { "architecture": "arm64", "os": "linux" } }, { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 526, "digest": "sha256:7f82fecd72730a6aeb70713476fb6f7545ed1bbf32cadd7414a77d25e235aaca", "platform": { "architecture": "ppc64le", "os": "linux" } }, { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 526, "digest": "sha256:1175fd4d728641115e2802be80abab108b8d9306442ce35425a4e8707ca60521", "platform": { "architecture": "s390x", "os": "linux" } } ]}Filter the result to extract the image digest for the platform that youwant. Get the digest of the image manifest for the
amd64CPU architectureand thelinuxoperating system:curl -s https://gcr.io/v2/google-containers/pause/manifests/3.2 | \ jq -r '.manifests[] | select(.platform.architecture=="amd64" and .platform.os=="linux") | .digest'The filtering in this command mimics how container runtimes,such ascontainerd,select the image that matches the target platform from the image index.
The output is similar to the following:
sha256:4a1c4b21597c1b4415bdbecb28a3296c6b5e23ca4f9feeb599860a1dac6a0108Theimage digest is the result of applying acollision-resistant hash to the image index or image manifest, typically theSHA-256 algorithm.
Get the digest of the image
gcr.io/google-containers/pause-amd64:3.2:curl -s https://gcr.io/v2/google-containers/pause-amd64/manifests/3.2 \ | shasum -a 256 \ | cut -d' ' -f1The output is similar to the following:
4a1c4b21597c1b4415bdbecb28a3296c6b5e23ca4f9feeb599860a1dac6a0108You can reference this image using the image digest value as follows:
gcr.io/google-containers/pause-amd64@sha256:4a1c4b21597c1b4415bdbecb28a3296c6b5e23ca4f9feeb599860a1dac6a0108Using thecontent-addressable storage concept, get the image manifest by using the digest as a reference:
curl -s https://gcr.io/v2/google-containers/pause-amd64/manifests/sha256:4a1c4b21597c1b4415bdbecb28a3296c6b5e23ca4f9feeb599860a1dac6a0108Many container image registries return the digest of manifests, imageindexes, configuration objects, and file system layers in the
Docker-Content-Digestheader in response to HTTPHEADrequests. Get thedigest of the image index of the imagegcr.io/google-containers/pause-amd64:3.2:curl -s --head https://gcr.io/v2/google-containers/pause/manifests/3.2 \ | grep -i Docker-Content-Digest \ | cut -d' ' -f2The output is similar to the following:
sha256:927d98197ec1141a368550822d18fa1c60bdae27b78b0c004f705f548c07814fThe
Docker-Content-Digestheader isnot mandated by the Open Container Initiative Distribution specifications,so this approach might not work with all container image registries. Youcan use it withArtifact Registry andContainer Registry.To retrieve an image configuration object using the digest value fromthe image manifest, do the following:
Get the configuration digest:
CONFIG_DIGEST=$(curl -s https://gcr.io/v2/google-containers/pause-amd64/manifests/3.2 \ | jq -r '.config.digest')Use the configuration digest to retrieve the configurationobject, and use
jqto format the output to make it easier to read:curl -sL https://gcr.io/v2/google-containers/pause-amd64/blobs/$CONFIG_DIGEST \ | jqThe output is similar to the following:
{ "architecture": "amd64", "config": { "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ], "Entrypoint": [ "/pause" ], "WorkingDir": "/", "OnBuild": null }, "created": "2020-02-14T10:51:50.60182885-08:00", "history": [ { "created": "2020-02-14T10:51:50.60182885-08:00", "created_by": "ARG ARCH", "comment": "buildkit.dockerfile.v0", "empty_layer": true }, { "created": "2020-02-14T10:51:50.60182885-08:00", "created_by": "ADD bin/pause-amd64 /pause # buildkit", "comment": "buildkit.dockerfile.v0" }, { "created": "2020-02-14T10:51:50.60182885-08:00", "created_by": "ENTRYPOINT [\"/pause\"]", "comment": "buildkit.dockerfile.v0", "empty_layer": true } ], "os": "linux", "rootfs": { "type": "layers", "diff_ids": [ "sha256:ba0dae6243cc9fa2890df40a625721fdbea5c94ca6da897acdd814d710149770" ] }}
To retrieve file system layers using digest values from the imagemanifest, do the following:
Get the digest of the layer that you want to retrieve:
LAYER_DIGEST=$(curl -s https://gcr.io/v2/google-containers/pause-amd64/manifests/3.2 \ | jq -r '.layers[0].digest')Use the layer digest to retrieve the layer tar file, and listthe contents:
curl -sL https://gcr.io/v2/google-containers/pause-amd64/blobs/$LAYER_DIGEST \ | tar --listThis layer has only one file, called
pause.
To look up tags associated with an image digest, do the following:
Define the digest that you want to look up:
IMAGE_DIGEST=$(curl -s https://gcr.io/v2/google-containers/pause-amd64/manifests/3.2 \ | shasum -a 256 \ | cut -d' ' -f1)The
IMAGE_DIGESTenvironment variable contains the digest of the imagereferenced by the tag3.2.Use theimage tags list endpoint,
/tags/list,to list tag information, and extract the tags for the digest value:curl -s "https://gcr.io/v2/google-containers/pause-amd64/tags/list?n=1" \ | jq ".manifest.\"sha256:$IMAGE_DIGEST\".tag"The output is similar to the following:
[ "3.2"]
To get the manifest of an image from a Artifact Registry container imagerepository by using cURL, include anaccess token in the
Authorizationrequest header:curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" \ https://LOCATION-docker.pkg.dev/v2/PROJECT_ID/REPOSITORY/IMAGE/manifests/DIGEST
Replace the following:
LOCATION: the regional or multi-regionallocation of your repositoryPROJECT_ID: yourGoogle Cloud project IDREPOSITORY: your repository nameIMAGE: your image nameDIGEST: your image digest in the formatsha256:DIGEST_VALUE
What's next
- To learn more about images, see the Open Container InitiativeImage Format andDistribution specifications.
Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2026-02-18 UTC.