OCI Image Format Spec 解读
在 OCI 标准中,为描述 OCI Image规范包含了 image manifest,image index(optional),filesystem layers集合以及 configuration配置。通过如上描述使得对于 image 在异构场景下能够被构建、传输且可执行变的通用化。
站在上层应用的视角, image manifest 包含内容可寻址且解压可运行的filesystem layer。而 image configuration 包含例如应用参数、环境变量等。image index 则是对系列 manifest 和 descriptors 的描述指向,用于对不同镜像的补充,一般来说是对不同架构或者不同属性的描述。

Specification 解读
OCI Image Media Types
OCI Image Media Types 定义了如下的格式:
application/vnd.oci.descriptor.v1+json:Content Descriptorapplication/vnd.oci.layout.header.v1+json:OCI Layoutapplication/vnd.oci.image.index.v1+json:Image Indexapplication/vnd.oci.image.manifest.v1+json:Image manifestapplication/vnd.oci.image.config.v1+json:Image configapplication/vnd.oci.image.layer.v1.tar:"Layer", 以tar方式压缩application/vnd.oci.image.layer.v1.tar+gzip:"Layer", 以gzip方式压缩application/vnd.oci.image.layer.v1.tar+zstd:"Layer", 以zstd方式压缩application/vnd.oci.scratch.v1+json:Scratch blobapplication/vnd.oci.artifact.manifest.v1+json:Artifact manifest
而如下 media types 将被剔除且不建议在未来的版本中使用:
application/vnd.oci.image.layer.nondistributable.v1.tarapplication/vnd.oci.image.layer.nondistributable.v1.tar+gzipapplication/vnd.oci.image.layer.nondistributable.v1.tar+zstd
对于 media type 的明细配置矩阵可以参考 Compatibility Matrix。
各 Media Type 关联关系

通过 Descriptors 描述其中关联关系。其中 image-index 可以理解为是 **fat-manifest**,是对目标架构平台的 image manifests的关联描述入口。其中 image manifest 则是对具体 image configuration 和众多 layers 的描述关联入口。
spec 中上层组件描述
Image Manifest
构建容器镜像的一种文档描述,其作用有如下三点:
- 用于构建可内容寻址的镜像,镜像模型中包含可哈希获取镜像配置及其组件
- 通过
fat-manifest来维护各异构平台支持的镜像 - 可转换位
OCI运行时规范
属性介绍
image index 主要是一系列架构平台的信息描述,而 image manifest 则是维护具体镜像配置,以及在具体 operating system 的镜像的系列 layers 的信息。
shcemaVersion| int | REQUIREDmediaType| string | REQUIREDartifactType| string | OPTIONALconfig|descriptor| REQUIREDmediaType| string
layers| array of objects
其中元素必须是descriptor,且必须拥有一个入口 entry。subject|descriptor| OPTIONALannotation| string-string-map | OPTIONAL
Image Manifest 示例
1 | { |
**Note: mediaType 必须与所包含的 digest 相对应,比如当 digest 是通过 ScratchDigestSHA256 生成,那么 media type “必须” 配置为 application/vnd/oci.scratch.v1+json**。
1 | { |
OCI Image Index 解读
image index 的配置设置是作为 image manifests 的上层引用。
具体属性解读
schemaVersion| int | REQUIREDmediaType| stringmanifests| array of objects | REQUIREDmanifests包含系列 带有如下属性的descriptor propertiesmediaType| stringplatform| obeject | OPTIONAL
当具体platform被提供时,需要进行如下运行时资源声明architecture| string | REQUIREDos| string | REQUIREDos.version| string | OPTIONALos.features| array of strings | OPTIONALvariant| string | OPTIONALfeatures| array of strings
annotations| string-string-map | OPTIONAL
Platform Variants
| ISA/ABI | architecture | variant |
|---|---|---|
| ARM | 32-bit, v6 | arm |
| ARM | 32-bit, v7 | arm |
| ARM | 32-bit, v8 | arm |
| ARM | 64-bit, v8 | arm64 |
OCI Image Index 示例
- simple image index with two platforms
1 | { |
- image index with multiple media types
1 | { |
OCI Image Layout Specification 解读
通过 image layout 及 ref 即可构建一个 OCI Runtime Specification bundle:
- 通过 image index 查询 manifest
- 通过定义的 layers 使用 filesystem layers
- 通过
image-confing.json转换为 OCI Runtime Specification
内容解读
image layout 包含如下内容:
blogs目录:- content-addressable blobs
- blog has no schema
- 目录必须存在但可能为空
oci-layout文件- 必须存在
- 必须为 JSON 对象
- 必须包含
imageLayoutVersion字段 - 可能还包含其他字段
index.json文件- 必须存在
- 必须为 image index 对象
示例
1 | $ cd example.com/app/ |
Blogs 解读
blogs的目录中包含由SHA算法生成的各个包含实际内容的子目录组织而成。blog/<alg>/<encoded>必须与digest <alg>:<encoded>相匹配,比如 contentblobs/sha256/da39a3ee5e6b4b0d3255bfef95601890afd80709必须与 digestsha256:da39a3ee5e6b4b0d3255bfef95601890afd80709相匹配.
示例
1 | $ cat ./blobs/sha256/9b97579de92b1c195b85bb42a11011378ee549b02d7fe9c17bf2a6b35d5cb079 | jq |
1 | $ cat ./blobs/sha256/afff3924849e458c5ef237db5f89539274d5e609db5db935ed3959c90f1f2d51 | jq |
1 | $ cat ./blobs/sha256/5b0bcabd1ed22e9fb1310cf6c2dec7cdef19f0ad69efa1f392e94a4333501270 | jq |
oci-layout file
示例
1 | { |
index.json file
示例
1 | { |
Image Layer Filesystem Changeset
+gzip Media Types
application/vnd.oci.image.layer.v1.tar+gzipapplication/vnd.oci.image.layer.nondistributable.v1.tar+gzip
+zstd Media Types
application/vnd.oci.image.layer.v1.tar+zstdapplication/vnd.oci.image.layer.nondistributable.v1.tar
Change Types
changes 类型:
- Additions
- Modifications
- Removals
其中 Additions 和 Modifications 在改变集中是相同的表现,而 Removals 则通过 “whiteout” 标识。
File Types
- regular files
- directories
- sockets
- symbolic links
- block devices
- character devices
- FIFOs
File Attributes
Additions 和 Modifications 必须包含额属性:
- Modification Time(
mtime) - User ID(
uid)- User Name(
uname)
- User Name(
- Group ID(
gid)- Group Name(
gname)
- Group Name(
- Mode(
mode) - Extended Attributes(
xattrs) - Symlink reference(
linkname+ symbolic link type) - Hardlink reference(
linkname)
Creating
Initial Root Filesystem
initial root 作为基础或者父 layer。如下示例只是为了配合演示,其中的 root filesystem 只是一个初始化状态,为一个空目录。rootfs_c9d_v1/
Populate Initial Filesystem
目录和文件创建:
1 | rootfs-c9d-v1/ |
rootfs-c9d_v1/ 归档为 tar 包,包含如下内容:
1 | ./ |
Populate a Comparison Filesystem
创建一个新的目录,其中初始化内容为 rootfs-c9d_v1/。能够保留文件属性的示例命令如下:
- cp(1): cp -a rootfs-c9d-v1/ rootfs-c9d-v1.s1/
- rsync(1): rsync -aHAX rootfs-c9d-v1/ rootfs-c9d-v1.s1/
- tar(1): mkdir rootfs-c9d-v1.s1 && tar –acls –xattrs -C rootfs-c9d-v1/ -c . | tar -C rootfs-c9d-v1.s1/ –acls –xattrs -x (including –selinux where supported)
对 snapshot 的任何改变都不能改变或影响它所复制的目录。
如上 rootfs-c9d-v1.s1 作为 rootfs-c9d-v1 一个相同的快照,其将作为更新和改变做好准备。
Note: 写时复制或者联合文件系统可以高效地处理目录 snapshots
1 | rootfs-c9d-v1.s1/ |
在此演示中,向 /etc/my-app.d 中添加一个默认的配置文件,同时移除现有的配置文件。另外对 ./bin/my-app-tools 的二进制文件做出改变(文件属性或者文件内容)来演示 layout 变化,变化后内容如下:
1 | rootfs-c9d-v1.s1/ |
Determining Changes
当两目录进行比对时,相对路径根目录是顶层目录,查找哪些内容被添加、修改或者删除。
上述演示比对结果如下:
1 | Added: /etc/my-app.d/ |
Representing Changes
tar 归档文件将被创建且其中只会包含更改的文件集
其中 rootfs-c9d-v1.s1 显示如下:
1 | ./etc/my-app.d/ |
需要注意的是当更改集生效的时候需要保证 ./etc/my-app-config 已经被删除了,其文件前缀为 .wh.。
OCI Image Configuration
OCI image 是对 root filesystem 变化的有序集合且其中包含相应执行参数,可供容器运行使用。
关键术语
Layer
- 镜像文件系统由 layers 构成
- 每个 layer 对代表一组文件系统的变化,其格式为 tar 包,记录着文件的添加、修改或者删除
- layers 中并不包含配置的元数据,比如环境变量或者参数,这些将作为一个完整镜像时的属性,而不是在每个layer中有体现
- 使用基于层的或联合的文件系统,如AUFS,或通过计算文件系统快照的差异,文件系统的变化集可以被用来呈现一系列的image layers,就像它们是一个完整的文件系统
Image JSON
- 每个镜像将有一个关联的 JSON 结构体用来描述一些关于镜像的基础信息,如创建日期、作者,同时也可以包含一些运行时的配置例如执行入口、默认参数、网络和volume卷
- JSON 描述包含对每个 layer 加密哈希后的引用,用于对该镜像的历史信息的维护
- JSON 应该是不可变的
- 改变的话应该意味着一个新的派生镜像,而不是在原有的镜像上做出改变
Layer DiffID
layer 的 DiffID 是该层未压缩的 tar 归档的摘要,并以描述符摘要的格式进行序列化。
Layer ChainID
为方便起见,有时用一个标识符来指代一叠加的 layer 是很有用的。
ImageID
每个镜像的的ID是由其配置JSON的SHA256哈希值给出的。
属性
- created | string | OPTIONAL
- author | string | OPTIONAL
- architecture | string | REQUIRED
- os | string | REQUIRED
- os.version | string | OPTIONAL
- os.features | *array of strings | OPTIONAL
- variant | string | OPTIONAL
- config | object | OPTIONAL
- User | string | OPTIONAL
- ExposedPorts | object | OPTIONAL
- Env | array of strings | OPTIONAL
- Entrypoint | array of strings | OPTIONAL
- Cmd | array of strings | OPTIONAL
- Volume | object | OPTIONAL
- WorkingDir | string | OPTIONAL
- Labels | object | OPTIONAL
- StopSignal | string | OPTIONAL
- Memory | integer | OPTIONAL
- CpuShares | integer | OPTIONAL
- Healthcheck | object | OPTIONAL
- rootfs | object | REQUIRED
- created | string | OPTIONAL
- author | string | OPTIONAL
- created_by | string | OPTIONAL
- comment | string | OPTIONAL
- empty_layer | boolean | OPTIONAL
示例
1 | { |
Conversion to OCI Runtime Configuration
- 从 filesystem layers 提取 root filesystem
- 将 image configuration blob 转换为 OCI Runtime configuration blob
属性比对表
| Image Field | Runtime Field | Notes |
|---|---|---|
| Config.WorkingDir | process.cwd | |
| Config.Env | process.env | 1 |
| Config.Entrypoint | process.args | 2 |
| Config.Cmd | process.args | 2 |
Annotations Fields
| Image Field | Runtime Field | Notes |
|---|---|---|
| os | annotations | 1,2 |
| architecture | annotations | 1,3 |
| variant | annotations | 1,4 |
| os.version | annotations | 1,5 |
| os.features | annotations | 1,6 |
| author | annotations | 1,7 |
| created | annotations | 1,8 |
| Config.Labels | annotations | |
| Config.StopSignal | annotations | 1,9 |
Parsed Fields
| Image Field | Runtime Field |
|---|---|
| Config.User | process.user.* |
Optional Fields
| Image Field | Runtime Field | Notes |
|---|---|---|
| Config.ExposedPorts | annotations | 1 |
| Config.Volumes | mounts | 2 |
Annotations
关于注解的三种模式
Config.Labels-> configurationannotations-> manifestannotations-> image index
Descriptor
属性
- mediaType | string | REQUIRED
- digest | string | REQUIRED
- size | int64 | REQUIRED
- urls | array of strings | OPTIONAL
- annotations | string-string-map | OPTIONAL
- data | string | OPTIONAL
- artifactType | string | OPTIONAL
Digests 摘要
摘要命名规范
1 | digest ::= algorithm ":" encoded |
Digest 计算规则
1 | let ID(C) = Descriptor.digest |
其中 H 为具体 哈希算法
已注册的算法
| algorithm identifier | algorithm |
|---|---|
| sha256 | sha-256 |
| SHA512 | sha-512 |
示例
- 包含基础信息的 Manifest
1 | { |
- 带有指定 url 的 Manifest
1 | { |
- 带有 artifact 的 manifest
1 | { |
最后的话
其实个人把此作为 containerd 源码分析的番外篇,但是对于 OCI Image 部分的理解还是很有必要的,除了 containerd 相关的 OCI Interface 的定义,下沉到更加底层的操作,其实就是对此标准的封装。
