Images, Layers, Content-Addressable Storage, Manifests, Config Objects, and Image Identity: Guided Hands-On Workflow and Core Operations
This hands-on lesson turns image identity into evidence. You will pull a small Docker Official Image, capture its repository digest, inspect local and registry metadata, compare history with layer descriptors, create a disposable alias, and prove that a digest—not a tag—is the stable reference.
Learning objectives
- Pull a small versioned image and immediately capture the exact digest returned by the registry.
-
Compare local
docker image inspectevidence with registry-sidedocker buildx imagetools inspectevidence. -
Explain what
docker image historycan show and why it is not a complete manifest/provenance record. - Create and remove only a disposable local alias while proving the underlying image content remains referenced.
- Run the image by digest and preserve an evidence packet without depending on mutable tags.
1. Lab scope and safety boundary
This lab uses the Docker Official Image busybox:1.37.0.
The versioned tag is only a starting coordinate. You will capture
the digest that your registry returns and use that value for
immutable follow-up operations. You will not publish, mutate daemon
storage, use a production registry, or run broad prune commands.
devops-academy-image-id:ch04 and one container named
devops-academy-ch04. The pulled upstream image may
already exist on the learner's host, so cleanup deliberately does
not delete it.
2. Preflight: prove the active client, daemon, platform, and builder
docker context show
docker version
docker info --format 'OSType={{.OSType}} Arch={{.Architecture}} Driver={{.Driver}}'
docker buildx version
docker buildx ls
Record the active context and server architecture. If
docker version cannot reach a server, stop here and
repair Chapter 02 connectivity first. If Buildx is unavailable, the
local-inspection path still works, but registry-side index
inspection must be documented as “not observed” rather than
invented.
3. Capture before-state without deleting anything
SOURCE='busybox:1.37.0'
ALIAS='devops-academy-image-id:ch04'
NAME='devops-academy-ch04'
docker image ls --digests busybox
docker image inspect "$SOURCE" --format '{{json .RepoDigests}}' 2>/dev/null || true
docker ps -a --filter "name=^/${NAME}$"
The || true is used only for a read-only “may not
exist” observation. It is not used to hide a later lab failure.
Preserve the output so you can distinguish “already cached” from
“pulled during this lab.”
4. Pull the named image and capture registry identity
docker pull "$SOURCE"
docker image inspect "$SOURCE" \
--format 'ID={{.Id}}\nRepoDigests={{json .RepoDigests}}\nOS={{.Os}} Arch={{.Architecture}}\nRootFS={{json .RootFS}}'
The pull output should print a digest.
RepoDigests provides repository-qualified immutable
references recorded for the local image. Do not replace that
observed value with a digest copied from this lesson, because
multi-platform resolution and published content can change over
time.
Capture the first repository digest into a shell variable:
PINNED=$(docker image inspect "$SOURCE" --format '{{index .RepoDigests 0}}')
printf 'Pinned reference: %s\n' "$PINNED"
test -n "$PINNED"
5. Inspect the registry-side index/manifest graph
docker buildx imagetools inspect "$SOURCE"
docker buildx imagetools inspect --raw "$SOURCE" > ch04-registry-object.json
If the top-level object is an OCI index or Docker manifest list, note its digest and the child platform descriptors. If it is a single image manifest, note the config and layer descriptors directly. Media type tells you what kind of document you received; do not infer “multi-platform” from the tag name.
- Top-level digest and media type.
- Your host OS/architecture.
- The child manifest digest for your platform when an index is present.
- Config descriptor digest and ordered layer descriptor digests when visible.
6. Compare local ID, RepoDigest, and rootfs DiffIDs
docker image inspect "$SOURCE" --format 'ImageID={{.Id}}'
docker image inspect "$SOURCE" --format 'RepoDigests={{json .RepoDigests}}'
docker image inspect "$SOURCE" --format 'RootFS={{json .RootFS}}'
docker image inspect "$SOURCE" --format 'Created={{.Created}} User={{json .Config.User}} Cmd={{json .Config.Cmd}}'
The local Image ID/config identity, repository digest, and rootfs
DiffIDs answer different questions. The local config digest
describes the selected image configuration. The repository digest is
usable as a registry pull reference. The
RootFS.Layers values are DiffIDs for the uncompressed
filesystem changesets.
7. Use history as a build narrative, not manifest truth
docker image history --no-trunc "$SOURCE"
History can help explain how an image was assembled and which
metadata-only steps exist, but it is not a substitute for
manifest/config inspection. A history row can correspond to no
filesystem layer, and imported/BuildKit-produced images can show
<missing> image IDs in history. For exact content
identity, return to the manifest, config, and descriptor digests.
8. Create a disposable alias and prove reference sharing
docker tag "$PINNED" "$ALIAS"
docker image inspect "$SOURCE" --format 'source={{.Id}}'
docker image inspect "$ALIAS" --format 'alias={{.Id}}'
docker image ls --no-trunc "$ALIAS"
The two references should resolve to the same local image/config ID. Creating the alias did not duplicate every layer. It added another human-readable reference to existing content.
docker image rm "$ALIAS"
docker image inspect "$SOURCE" --format 'still-present={{.Id}}'
That final inspection proves removing the lab alias did not remove the upstream source reference or all shared content.
9. Run by the captured digest
docker rm -f "$NAME" 2>/dev/null || true
docker run --name "$NAME" "$PINNED" sh -c \
'printf "hello from digest-pinned busybox\n"; uname -m'
docker inspect "$NAME" --format 'Container={{.Id}} Image={{.Image}} Ref={{.Config.Image}} Exit={{.State.ExitCode}}'
.Config.Image preserves the reference used to create
the container; .Image is the local image ID/config
identity. The successful command proves the selected content can
execute on the current platform. It does not prove vulnerability
status, provenance, signature trust, or production readiness.
10. Challenge: classify each identifier
Without copying commands from above, collect four values: the tag, the top-level registry digest, the local Image ID, and one rootfs DiffID. For each, write one sentence that states what object it identifies and whether it can be used directly in a registry pull reference. If two values happen to look related, explain why byte-level content identity—not visual similarity—determines equivalence.
11. Guarded cleanup
docker inspect "$NAME" --format '{{.Name}} {{.Config.Image}}' 2>/dev/null || true
docker rm "$NAME" 2>/dev/null || true
docker image inspect "$ALIAS" >/dev/null 2>&1 && docker image rm "$ALIAS" || true
docker ps -a --filter "name=^/${NAME}$"
docker image ls "$ALIAS"
Do not run docker system prune, delete Docker data-root
files, or remove busybox:1.37.0 as part of this
checkpoint. The source image can predate the lab and may be shared
with unrelated work.
Knowledge check
Why capture RepoDigests immediately after the
pull?
It records the repository-qualified immutable identity that the daemon associated with the pulled content, so later operations are not dependent only on the mutable tag.
Why does deleting the disposable alias not necessarily free layer bytes?
The source tag, other images, containers, or snapshots may still reference the same content. Layers are content-addressed and shared.
What does a successful run by digest prove?
It proves the registry reference resolved to content that the daemon could obtain and execute for the selected platform. It does not prove trust, vulnerability status, provenance, or application health beyond that command.
Why should docker history not be used as the only
layer inventory?
History is build/configuration narrative data. Metadata-only history entries can have no filesystem layer, and exact distributed layer identities live in manifest descriptors.
Official references and version notes
- Docker: What is an image? — image/layer fundamentals and local image inspection.
- docker image pull — content-addressable image storage, shared layers, pull digests, and pulling by digest.
- docker image inspect — local image metadata, IDs, RepoDigests, rootfs data, and platform-aware inspection.
- docker image ls — repository/tag presentation, image IDs, and digest display.
- docker image history — build-history presentation and platform selection.
- docker buildx imagetools inspect — registry-side image index/manifest inspection without assuming the local store contains every platform.
- containerd image store with Docker Engine — Engine 29 fresh-install default, snapshotters, multi-platform local storage, and upgrade/userns-remap caveats.
- Docker storage drivers — layer sharing, copy-on-write context, history examples, and classic storage-driver behavior.
- OCI Image Specification v1.1.1 — current stable OCI image-format release used as the chapter's standards baseline.
- OCI image manifest — config descriptor, ordered layer descriptors, media types, and single-image/platform semantics.
- OCI image index — higher-level descriptor set used for multi-platform publication.
- OCI image configuration — runtime configuration, rootfs DiffIDs, history, and ImageID-related content.
- OCI content descriptors — media type, digest, size, platform, and content-verification semantics.
Verified 2026-09-21: Docker Engine 29.8.1 remains
the current Engine 29 patch line used by this course baseline.
Fresh Docker Engine 29 installations use the containerd image
store by default, while upgraded older daemons can retain the
classic storage-driver store; userns-remap is a
documented exception. OCI Image Specification
v1.1.1 is the current stable release. The
mandatory lab uses the Docker Official Image
busybox:1.37.0 only as a small human-readable
starting reference, then captures and uses the registry-provided
digest at run time. Always record the actual daemon, storage
backend, platform, Buildx version, media types, and resolved
digests observed on the learner's system.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.