Images, Layers, Content-Addressable Storage, Manifests, Config Objects, and Image Identity: Concepts, Architecture, and Mental Model
Container images become operationally trustworthy only when you distinguish mutable names from immutable content. This lesson builds the image graph from a tag through an OCI index or manifest, config object, ordered layer descriptors, local content/snapshot storage, and finally the root filesystem a container receives.
Learning objectives
- Explain the path from a human-readable repository/tag through an OCI image index or image manifest to a config object and ordered layer descriptors.
- Distinguish a tag, index digest, platform-manifest digest, config digest/Image ID, compressed layer digest, and uncompressed DiffID.
- Explain why a container root filesystem is assembled from ordered immutable changesets plus a writable container layer rather than copied from one monolithic image file.
- Use read-only Docker/Buildx inspection to determine the current platform, local image identity, RepoDigests, rootfs DiffIDs, and registry-side manifest structure.
- Relate digest-level identity to reproducible CI/CD promotion, rollback, audit evidence, and supply-chain verification.
1. The problem: a tag is a pointer, not the bytes
Humans prefer names such as busybox:1.37.0. Automation
needs something stronger. A repository name and tag are registry
lookup coordinates: the registry can later make that same tag
resolve to different content. That mutability is useful for release
channels such as stable or 3.24, but it is
insufficient evidence for a forensic question such as “which exact
image did production run?”
A content digest answers a different question. It is computed from the bytes of a specific content object. Change the object and the digest changes. OCI uses this property repeatedly: indexes reference manifests by descriptor digest; manifests reference config and layer blobs by digest; the config references uncompressed filesystem DiffIDs. Reproducibility begins by naming which digest you mean.
2. The image graph from name to runnable filesystem
The most useful mental model is a directed graph of immutable content with a mutable human-readable entry point. The tag is resolved first. A multi-platform publication normally resolves to an image index; the index chooses a platform-specific image manifest; that manifest references one config blob plus ordered layer descriptors. Docker then ensures the selected blobs exist locally and prepares snapshots/rootfs state that a container can use.
flowchart TD
A[repository:tag] -- mutable lookup --> B[registry/local resolver]
B --> C{index or manifest?}
C -- multi-platform --> D[OCI image index]
D -- platform descriptor --> E[platform image manifest]
C -- single-platform --> E
E -- config descriptor --> F[image config JSON]
E -- ordered layer descriptors --> G[compressed layer blobs]
F -- rootfs.diff_ids --> H[uncompressed changeset identities]
G -- pull + verify + unpack --> I[local content/snapshot store]
I -- mount/assemble --> J[container read-only root filesystem]
J -- plus writable layer --> K[running container filesystem view]
Each arrow represents a verification or selection boundary. The registry can return an index that contains many platforms, while the local daemon may materialize only one platform. A successful tag lookup does not prove the desired platform exists; a successful manifest fetch does not prove all layer blobs unpacked; local image presence does not prove a container is running.
3. Six identities that beginners often collapse into one
| Identity | What it names | Mutable? | Typical evidence |
|---|---|---|---|
| Repository + tag |
A named registry reference such as
busybox:1.37.0.
|
Yes; the publisher can move the tag. | docker image ls, pull input. |
| Index digest | A multi-platform OCI image index / Docker manifest list. | No for those exact bytes. | docker buildx imagetools inspect. |
| Manifest digest | One platform-specific image manifest with config + layer descriptors. | No for those exact bytes. | Index child descriptor or registry response. |
| Config digest / Image ID | The image configuration JSON used by the selected image; Docker exposes a content-addressed local image ID. | No for those exact config bytes. | docker image inspect --format '{{.Id}}'. |
| Layer digest | A distributed layer blob as referenced by the manifest, commonly compressed. | No. | Manifest descriptors / imagetools --raw. |
| DiffID | The digest of the uncompressed layer tar changeset. | No. |
.RootFS.Layers in local image inspection / OCI
config.
|
These values can all start with sha256: and still not
be interchangeable. The algorithm prefix tells you how the digest is
calculated, not what semantic object it identifies.
4. OCI descriptors: the repeated contract
OCI descriptors make the graph verifiable. A descriptor carries at least a media type, digest, and byte size. The consumer can know what representation to expect, how much content should arrive, and which cryptographic digest the received bytes must match. Indexes and manifests are therefore not vague catalogs; they are typed, content-addressed maps to other objects.
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"digest": "sha256:<content-hash>",
"size": 123456
}
The example is schematic on purpose. Do not paste a digest from a tutorial and assume it identifies your platform's layer. Capture the descriptors returned for the exact image and platform you are inspecting.
5. Image index versus image manifest
An image index is a higher-level document whose manifest descriptors can carry platform metadata such as operating system and architecture. This is how one tag can support Linux/amd64, Linux/arm64, and other variants. An image manifest describes one image: a config descriptor and an ordered list of layer descriptors. A single-platform publication can resolve directly to a manifest without an index.
This difference explains a common puzzle: the digest printed for a multi-platform tag can differ from the digest of the manifest actually pulled for your host platform. Both can be correct; they name different nodes in the graph.
6. Config object, Image ID, history, and DiffIDs
The OCI config JSON contains runtime-oriented metadata such as
environment, entrypoint/command fields, working directory, user,
plus a rootfs structure with ordered
diff_ids. A DiffID is computed over the uncompressed
tar changeset, whereas a layer descriptor digest usually identifies
the distributed compressed blob. Compression changes bytes, so the
two digests should not be expected to match.
The config also contains history entries. Some history entries represent metadata-only build steps and have no filesystem layer. That is why “number of history rows” and “number of layer blobs” are not guaranteed to be the same.
docker image inspect busybox:1.37.0 \
--format 'ID={{.Id}}\nRepoDigests={{json .RepoDigests}}\nRootFS={{json .RootFS}}'
7. Layers are changesets, not mini virtual disks
Each image layer describes filesystem additions, modifications, and deletions relative to the state below it. Docker combines the ordered changes to present a coherent read-only root filesystem to the container. Starting a container adds a separate writable layer; mutating that writable layer does not mutate the image.
Layer reuse is one reason content addressability matters operationally. Two local references or images can share blobs. Removing one reference therefore does not imply the shared content bytes should disappear immediately. Conversely, deleting storage directories by hand can corrupt many images at once because the store is not a folder-per-image model.
8. Local image store: inspect before assuming
Docker Engine 29 uses the containerd image store by default on fresh
installations. Upgrades from older Engine versions can keep the
classic graph-driver store until explicitly migrated, and
userns-remap is a documented exception. The same CLI
concepts—references, IDs, pulls, runs—remain useful, but disk layout
and multi-platform local-storage capability can differ.
docker version
docker context show
docker info --format 'StorageDriver={{.Driver}}'
docker info | sed -n '/Storage Driver/p;/containerd image store/p'
Use the output as environment evidence. Do not teach a learner to
infer the store by opening or editing /var/lib/docker;
direct mutation bypasses Docker's metadata and lifecycle rules.
9. Read-only inspection sequence
Before pulling or deleting anything, establish the active context and existing local reference. Then inspect the registry-side graph and the local image separately. The following commands are observations, not cleanup commands:
SOURCE='busybox:1.37.0'
docker context show
docker version
docker image ls --digests busybox
docker buildx imagetools inspect "$SOURCE"
docker image inspect "$SOURCE" 2>/dev/null || true
If the image is absent locally, the final command failing does not contradict registry availability; it proves only that the active daemon does not currently have a matching local image object/reference.
10. DevOps use: bind release evidence to immutable identity
A strong delivery record can state: source revision X produced image index digest Y; tests/scans/attestations were evaluated for subject digest Y or a documented platform manifest; the registry accepted that content; staging and production resolved the intended digest; runtime evidence records the actual image identity. Tags can remain as convenient channels, but they should not be the only audit key.
Repository and tag make images discoverable.
Digest makes exact bytes addressable and verifiable.
Index → manifest proves which OS/architecture variant is intended.
Container inspection proves which image object the runtime used.
Knowledge check
A tag and a digest both point to an image. Why are they not equivalent release evidence?
A tag can be reassigned; a digest identifies the exact bytes of a specific content object. The digest also needs semantic context: index, manifest, config, or layer.
Why can an index digest differ from the manifest digest used by your amd64 host?
The index is a higher-level object containing descriptors for multiple platform manifests. Your host selects one child manifest, which has its own digest.
Why can a manifest layer digest differ from the corresponding DiffID?
The manifest digest identifies the distributed layer blob, often compressed; the DiffID hashes the uncompressed tar changeset.
Does removing one tag necessarily delete all layer bytes it referenced?
No. Other tags, images, containers, or snapshots can still reference shared content. Docker decides content lifecycle from references and store state.
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.