预备动作
ctr 下载镜像,导出为压缩包。并解压到文件夹。
镜像文件层级
image-spec/image-layout.md at main · opencontainers/image-spec · GitHub
镜像布局的结构如下:
$ tar xvf wg.tar -C wg-image
blobs/sha256/0303a59d29548085675c8dc77b594cfdaed591c2d3dc2eedb7f86423d68d4217
blobs/sha256/0350af939280a3c1cd93680faa5890636e2b2e1853c59bfa543fbf1dd3022123
blobs/sha256/0c885228653809eeb06ad27eca297d2dcc22e7e46056f420a83ead31d674eff7
blobs/sha256/0ff5eb3a6b4475e3dbd12f3e2683ea873ed76e3ad34a7b81a31ea77d98034d4b
blobs/sha256/2d2e0fc760791a12a90fa8101ab88f8e8dfc178539d0b3ead91f0394b124da81
blobs/sha256/38ae9c4bfd7c2b34961b19ff96a4e8930eb545b81a08a42e680beca6327eea43
blobs/sha256/5b7522ab11647cb4fc176d2817b3425b6a03bec4cced283746f0bf9b1767d1d0
blobs/sha256/96d9ee2f8e97cc43d61fe2c01555543a411ee2662f4ffb514b9580200c2692d2
blobs/sha256/9a36f2af670028da7e5201a9ad40616f66a2e07af074439103f3b0ead5d61a26
blobs/sha256/bed0e8f20ee92bd6b5867a0f0bd8f6cb3490b103539b1607f1621e3493ccd19f
blobs/sha256/e0fb2429c802bef7d81813dfd5a6a4e3f9b06b86b103a87c02cfbecc5cc9150e
blobs/sha256/fc515c5e05210d9f5f813831bc05ec38810e226c4715582e8d36ee42ceccec1c
index.json
manifest.json
oci-layout
blobs
目录blobs
子目录中的对象名称由每种哈希算法的目录组成,其子目录将包含实际内容。blobs/<alg>/<encoded>
中的内容必须与摘要<alg>:<encoded>
匹配。- 目录可能包含未被任何引用所引用的 Blob。
- 如果缺少引用的 Blob,则应通过外部 Blob 存储来补充。
oci-layout
文件- 该 JSON 对象作为开放容器镜像布局的标记,并提供正在使用的镜像布局版本。
imageLayoutVersion
值将与 OCI 镜像规范版本对齐,并在需要更改镜像布局时进行固定。
- 该 JSON 对象作为开放容器镜像布局的标记,并提供正在使用的镜像布局版本。
index.json
文件- 这是一个必需的文件,作为镜像布局的引用和描述符的入口点。该索引提供了一个已建立的路径(
/index.json
),以便在镜像布局中发现辅助描述符(auxiliary descriptors)。 - 每个描述符对象的
mediaType
字段将是index
或manifest
- 这是一个必需的文件,作为镜像布局的引用和描述符的入口点。该索引提供了一个已建立的路径(
manifest.json
文件- Docker 格式镜像使用的 manifest.json,
ctr image export
时会默认生成,可以增加--skip-manifest-json
参数不生成此文件。 - 在containerd InportIndex函数导入index时,若存在
oci-layout
则不会读取本文件。否则认为是 Docker v1.1 或 v1.2 的镜像格式,会读取本文件,并转换为OCI格式处理。
- Docker 格式镜像使用的 manifest.json,
OCI镜像各个类型的组织形式:
index
image index是一个高层级的manifest,用于指向特定的 image manifest,以支持一个或多个平台。
mediaType为 application/vnd.oci.image.index.v1+json
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.index.v1+json",
"manifests": [
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"size": 7143,
"digest": "sha256:e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f",
"platform": {
"architecture": "ppc64le",
"os": "linux"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"size": 7682,
"digest": "sha256:5b0bcabd1ed22e9fb1310cf6c2dec7cdef19f0ad69efa1f392e94a4333501270",
"platform": {
"architecture": "amd64",
"os": "linux"
}
}
],
"annotations": {
"com.example.key1": "value1",
"com.example.key2": "value2"
}
}
schemaVersion
int 这是一个必需属性,指定图像清单的模式版本。对于本规范的版本,这必须是2
,以确保与旧版本 Docker 的向后兼容性。此字段的值将不会改变,未来的规范版本中可能会移除此字段。mediaType
string 此属性应被使用,并与本规范的早期版本及其他类似外部格式保持兼容。当使用时,此字段必须包含媒体类型application/vnd.oci.image.index.v1+json
。该字段的用法与描述符的mediaType
使用不同。manifests
array of objects 此必需属性包含特定平台的图像清单列表。虽然该属性必须存在,但数组的大小可以为零。manifests
中的每个对象包括一组描述符属性,具有以下附加属性和限制:mediaType
string 此描述符属性有额外的限制。实现必须至少支持以下媒体类型:application/vnd.oci.image.manifest.v1+json
实现应支持以下媒体类型:application/vnd.oci.image.index.v1+json
(嵌套索引)
关注可移植性的图像索引应使用上述媒体类型之一。未来版本的规范可能会使用不同的媒体类型(即新的版本格式)。遇到未知的
mediaType
不应导致实现错误。platform
对象 此可选属性描述图像的最低运行时要求。如果目标是特定平台,则此属性应存在。architecture
string 此必需属性指定 CPU 架构。图像索引应使用,并且实现应理解,在 Go 语言文档中列出的值。os
string 此必需属性指定操作系统。图像索引应使用,并且实现应理解,在 Go 语言文档中列出的值。os.version
string 此可选属性指定目标操作系统的版本。实现可能拒绝使用os.version
不知道与主机 OS 版本兼容的清单。有效值由实现定义。例如,在 Windows 上为10.0.14393.1066
。
如果多个清单符合客户端或运行时的要求,则应使用第一个匹配条目。
annotations
字符串-字符串映射 此可选属性包含图像索引的任意元数据。此可选属性必须使用注释规则。
另外像以下 wireguard 在index中使用了 vnd.docker.distribution.manifest.list.v2+json
这一类型的数据,也被称为fat manifest
。
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.index.v1+json",
"manifests": [
{
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
"digest": "sha256:0c885228653809eeb06ad27eca297d2dcc22e7e46056f420a83ead31d674eff7",
"size": 685,
"annotations": {
"containerd.io/distribution.source.lscr.io": "linuxserver/wireguard",
"io.containerd.image.name": "lscr.io/linuxserver/wireguard:legacy",
"org.opencontainers.image.ref.name": "legacy"
}
}
]
}
manifest
manifest有三个用处。 第一个用处是内容可寻址的image; 第二个用处是支持不同的platform; 第三个用处是可转换为 OCI 运行时规范。
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"digest": "sha256:517b897a6a8312ce202a85c8a517d820b0fc5b6f5d14ec2a3267906f75680403",
"size": 372
},
"layers": [
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"digest": "sha256:430378704d12f9a980f41ae1a29c587974e1f0234d5dab0765fa95a4d764622e",
"size": 2155944
}
],
"annotations": {
"org.opencontainers.image.url": "https://github.com/docker-library/busybox",
"org.opencontainers.image.version": "1.37.0-glibc"
}
}
config
config
用于指定镜像配置,application/vnd.oci.image.config.v1+json
例如上文的sha256:517b897a6a8312ce202a85c8a517d820b0fc5b6f5d14ec2a3267906f75680403
记录如下:
{
"config": {
"Cmd": [
"sh"
]
},
"created": "2024-09-26T21:31:42Z",
"history": [
{
"created": "2024-09-26T21:31:42Z",
"created_by": "BusyBox 1.37.0 (glibc), Debian 12"
}
],
"rootfs": {
"type": "layers",
"diff_ids": [
"sha256:dab88e68d7096681d624de8bd542df9d91bae06c739a73483b6fb0e6869421ea"
]
},
"architecture": "amd64",
"os": "linux"
}
其中内容也是可以明白的。其中rootfs 中的layers 又是一堆分平台的manifests,同样会回到本章描述的 manifest
layers
layers
指定了本镜像的各个层级。其类型为
application/vnd.oci.image.layer.v1.tar
application/vnd.oci.image.layer.v1.tar+gzip
application/vnd.oci.image.layer.v1.tar+zstd
application/vnd.oci.image.layer.nondistributable.v1.tar
application/vnd.oci.image.layer.nondistributable.v1.tar+gzip
application/vnd.oci.image.layer.nondistributable.v1.tar+zstd
nondistributable
表示不可分发,不会上传到网络中。
gzip
/ zstd
为压缩格式。
使用 tar 即可看到该层文件,使用正则过滤一层目录:
$ tar -tf busybox-image/blobs/sha256/430378704d12f9a980f41ae1a29c587974e1f0234d5dab0765fa95a4d764622e | grep -P "^[a-z]+/$"
bin/
dev/
etc/
home/
lib/
root/
tmp/
usr/
var/
后续
结合busybox和wireguard镜像分析 OCI 镜像规范后,实际会存在很多疑问。例如
manifest.json
是什么,怎么处理的。(上文大致有写)vnd.docker.distribution.manifest.list.v2+json
这类媒体类型应该怎么处理。- OCI镜像 / Docker镜像在 containerd 中怎么做到兼容的,又怎么下发为 OCI运行时标准给 runc的。
.config.StopSignal
and.config.Labels
这种被称为 意外写入 Docker v1.2镜像标准 的配置,在未来会怎么去处理。
这些疑问都需要进现在首选的 high-level 运行时 containerd 代码里去看。
参考资料
- image-spec/layer.md at main · opencontainers/image-spec · GitHub
- image-spec/manifest.md at main · opencontainers/image-spec · GitHub
- image-spec/image-layout.md at main · opencontainers/image-spec · GitHub
- image-spec/image-index.md at main · opencontainers/image-spec · GitHub
- image-spec/media-types.md at main · opencontainers/image-spec · GitHub
- K8S 1.20 弃用 Docker 评估之:Docker 和 OCI 镜像格式的差别-腾讯云开发者社区-腾讯云