manifest: Describes the metadata of the image, which helps the client or container runtime verify the integrity and contents of the image.
config: Contains the instructions used during the image build process (for example, each line of a DockerFile), along with information such as the image’s history and runtime environment.
blob: The compressed files for each layer of the image, usually packaged with gzip.
1.2 containerd Image Storage Process
The containerd image storage process consists of two steps: Saving the original image and Unpacking the image to create snapshots.
The diagram below shows the key steps and file storage locations in the containerd image storage process, where the content store is containerd’s content storage area, and snapshots represent the snapshot storage area. A snapshot can be understood as a decompressed layer of the image.
1.2.1 Saving the Original Image
First, the manifest, config, and blob are stored in the content store, the default path is:
At the same time, the image metadata (digest, size) and content metadata (label, size) are stored in the meta.db file. This file is in the format of a bbolt database, the path is:
Each layer of the blob is unpacked, and its content is stored in the snapshots directory. The Snapshotter manages the image’s layered file system, with the default Snapshotter being overlayfs. The files are stored at:
The metadata of the snapshots (parent, child, digest) is saved in both /var/lib/containerd/io.containerd.metadata.v1.bolt/meta.db and io.containerd.snapshotter.v1.overlayfs/metadata.db.
When a container is generated, a snapshot is created based on the top layer of the image to serve as the container’s file system.
2 image content in the disk
Here, we take the kindest/kindnetd:v20240202-8f1494ea image as an example to explain how it is stored in a Linux environment.
2.1 Storage Directory
The default storage directory for containerd is /var/lib/containerd, which stores data related to the content, CRI, introspection, metadata, runtime, and snapshotter modules.
Regardless of whether the image is imported or pulled, the raw image content is ultimately stored in the io.containerd.content.v1.content directory, while the image metadata is stored in the io.containerd.metadata.v1.bolt/meta.db file.
Using the ctr command to view the image list, this data is read from the io.containerd.metadata.v1.bolt/meta.db file:
Opening the io.containerd.metadata.v1.bolt/meta.db file with boltbrowser, the images stored under the v1 → k8s.io → images path include labels, digest, and media type for each image. The digest for kindest/kindnetd:v20240202-8f1494ea is 61f9956af8019caf6dcc4d39b31857b868aaab80521432ddcc216b805c4f7988.
CAUTION
Be sure to stop the containerd process before opening the io.containerd.metadata.v1.bolt/meta.db file, as only one process can access it in read-write mode. Since containerd opens the file in read-write mode, this is detailed in issue 228.
2.3 Image Content in the content Directory
The image data is stored in the /var/lib/containerd/io.containerd.content.v1.content/blobs/sha256/{digest} path.
2.3.1 Manifest Index
The manifest index for the image is stored at /var/lib/containerd/io.containerd.content.v1.content/blobs/sha256/61f9956af8019caf6dcc4d39b31857b868aaab80521432ddcc216b805c4f7988.
NOTE
If the image’s type is application/vnd.docker.distribution.manifest.list.v2+json, it indicates that the image supports multiple platforms, and its digest is the manifest index (containing multiple manifest entries).
If the type is application/vnd.docker.distribution.manifest.v2+json, the image supports a single platform, and its digest points to the manifest.
The content is identical to what is retrieved from Docker Hub, and 61f9956af8019caf6dcc4d39b31857b868aaab80521432ddcc216b805c4f7988 is the value of the docker-content-digest header in the HTTP response.
This is identical to what is retrieved from Docker Hub, as the docker-content-digest in the HTTP response header is also bdddbe20c61d325166b48dd517059f5b93c21526eb74c5c80d86cd6d37236bac.
In order to find the corresponding file through the image, containerd maintains the relationship between the directory and the image. This is the metadata of content. The metadata of content contains the size of the mirror image content, creation time, and label.
The label of content stores the correlation relationship of various components of the image, the decompressed digest of the blob, and the corresponding relationship between the image and the snapshot. You can use ctr to view the label of each component of the image in content. This data is also read from the io.containerd.metadata.v1.bolt/meta.db file.
The image storage metadata in the io.containerd.metadata.v1.bolt/meta.db file is located at the path: v1 → k8s.io → content → blob.
2.4.1 Public Label
containerd.io/distribution.source.docker.io=kindest/kindnetd indicates that this content belongs to the kindest/kindnetd image on Docker Hub. This label is only added if the content was pulled from a registry. If the image was imported, it will not have this label. The format of the label is containerd.io.distribution.source.<registry>=[<repo/1>,<repo/2>]. If multiple images share the same digest, the image names are separated by commas, such as containerd.io/distribution.source.docker.io=kindest/kindnetd,public/kindnetd.
2.4.2 Manifest Index Label
containerd.io/gc.ref.content.m.<index> represents the digest of the manifest content for each platform. In this case, there are two platforms: linux/amd64 and linux/arm64.
containerd.io/gc.ref.content.config represents the digest of the config content.
containerd.io/gc.ref.content.l.<index> represents the digest of each image layer.
The platform in this case is linux/amd64, so the labels for the manifest with digest sha256:bdddbe20c61d325166b48dd517059f5b93c21526eb74c5c80d86cd6d37236bac are as follows:
containerd.io/uncompressed represents the digest value after the content of the layer is decompressed. The digest is calculated with the command cat <file> | gunzip - | sha256sum.
For example, the final layer content sha256:c2420332d0c7405cccc405b98ff4a1867bd103cbe571f03ac04b7e1cc7408e76 has the following label:
Since each image layer is compressed and immutable, it cannot be directly used by a container. The image must be mounted as a filesystem for the container to use it. This process is called “snapshotting,” and in containerd, each layer of the image is a snapshot, with each lower layer serving as the parent of the layer above. The default snapshotter used is overlayfs.
The snapshot’s digest is calculated by merging the data from the parent layer. Therefore, the first layer’s digest is the value of containerd.io/uncompressed, while the other layers’ snapshot digests will differ from the corresponding containerd.io/uncompressed values. The digest of the topmost layer’s snapshot is stored in the label containerd.io/gc.ref.snapshot.overlayfs in the config.
A snapshot’s kind can be Committed (immutable) or Active (read-write).
Since this image has four layers, there are also four snapshots. The bottom snapshot has the digest sha256:e4a5933ff9603ec98b5df28cf7c07c7be52fc15146020cabafb94e0dbb844e19, which matches the label value of containerd.io/uncompressed for the first image layer (sha256:b6425c1785a5de9285e14b515ddb6135b93ca5dd9edb744e1d1916a7a3687405), and its parent is empty.
The topmost snapshot, sha256:98b2b8dceda4d797430d2160aff66d6ad2eaaee440072f10c3fbbc56a338b951, is recorded in the config under the label containerd.io/gc.ref.snapshot.overlayfs.
The output of the ctr command is retrieved from the file io.containerd.metadata.v1.bolt/meta.db, under the path v1 → k8s.io → snapshots → overlayfs. It records information such as children, name, and parent.
The value of name is used as the key in the path io.containerd.snapshotter.v1.overlayfs/metadata.db under snapshots.
The id here represents the snapshot’s path in the filesystem. The IDs for each layer snapshot are as follows:
# ls /var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/71/fs/LICENSES
# ls /var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/70/fs/LICENSES
# ls /var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/69/fs/bin/kindnetd
# ls /var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/68/fs/bin boot dev etc go-runner home lib lib64 proc root run sbin sys tmp usr var
3 Container Creation
When a container is created, an Active snapshot is generated, with its parent being the final image snapshot.
In this example, there are two containers, resulting in two snapshots. The snapshot name corresponds to the container ID, and both containers have sha256:98b2b8dceda4d797430d2160aff66d6ad2eaaee440072f10c3fbbc56a338b951 as their parent.
For the container 17bb90bf08d8be9c4e4bf36dae6239bbe0322a735899ece4193b76fe9715, a snapshot directory /var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/174 was created as the upperdir and workdir for overlay.
1
2
3
4
5
# mount |grep 17bb90bf08d8be9c4e4bf36dae6239bbe0322a735899ece4193b76fe9715overlay on /run/containerd/io.containerd.runtime.v2.task/k8s.io/17bb90bf08d8be9c4e4bf36dae6239bbe0322a735899ece4193b76fe9715a98f/rootfs type overlay (rw,relatime,lowe
rdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/71/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/70/fs:/var/lib/co
ntainerd/io.containerd.snapshotter.v1.overlayfs/snapshots/69/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/68/fs,upperdir=/var/lib/container
d/io.containerd.snapshotter.v1.overlayfs/snapshots/174/fs,workdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/174/work)
4 Summary
The storage of containerd images includes the original image content, the decompressed image files, and related metadata.
The original image content (pulled or imported images) is stored in the io.containerd.content.v1.content directory.
The decompressed image content is stored in the io.containerd.snapshotter.v1.overlayfs directory (with overlay being the default storage driver on Linux).
Image-related metadata (including images, contents, and snapshots) is stored in the io.containerd.metadata.v1.bolt/meta.db file.
The metadata for each image layer snapshot (directory ID, kind, size, parent, etc.) is stored in the io.containerd.snapshotter.v1.overlayfs/metadata.db file.
When a container is created, a new snapshot is generated on top of the topmost image layer snapshot, which is used as the container’s filesystem.