OCI规范 镜像规范
容器OCI规范 镜像规范前言OCI 镜像规范初步OCI 文件类型Media TypeMedia Type 的不一致OCI Content DescriptorContent Descriptor 属性摘要和校验Content Descriptor 示例OCI 镜像布局规范详细内容示例Blobs 文件夹Blobs 示例oci-layout 文件oci-layout 示例indexjson 文件ind
容器OCI规范 镜像规范
整篇文章还没有润色,条理性还不够强,Image Layerd的规范还没来得及写。还只是半成品,先放出来给有兴趣的同学看一下。
前言
- OCI 官网:https://www.opencontainers.org/
- OCI 镜像规范:https://github.com/opencontainers/image-spec
- OCI 镜像规范的主要目的是:统一各种容器工具的镜像格式,让标准镜像能够在多种容器软件下使用。
- OCI 镜像规范中还给出了Go语言描述的对象模型示例。(Go,亲儿子)
OCI 镜像规范初步
从一个比较高层次的角度来看这个规范,主要有以下内容:
- 一个镜像由四部分组成:Manifest、Image Index (可选)、Layers、Configuration。
- 根据存储内容的密码学哈希值找到镜像存储的位置,根据内容寻址的描述格式。(Content Descriptors)
- 一种格式存储CAS斑点和引用它们(可选OCI层)
- 签名是基于签名的图像内容的地址(可选OCI层)
- 命名是联合基于DNS,可以授权(可选OCI层)
Manifest 包括镜像内容的元信息和镜像层的摘要信息,这些镜像层可以解包部署成最后的运行环境。
Configuration 则包含了应用的参数环境。
Index 则从更高的角度描述了Manifest,主要应用于镜像跨平台。
OCI 文件类型
Media Type
application/vnd.oci.descriptor.v1+json
: Content Descriptor(内容描述文件)application/vnd.oci.layout.header.v1+json
: OCI Layout(布局描述文件)application/vnd.oci.image.index.v1+json
: Image Index(高层次的镜像元信息文件)application/vnd.oci.image.manifest.v1+json
: Image Manifest(镜像元信息文件)application/vnd.oci.image.config.v1+json
: Image Config(镜像配置文件)application/vnd.oci.image.layer.v1.tar
: Image Layer(镜像层文件)application/vnd.oci.image.layer.v1.tar+gzip
: Image Layer(镜像层文件), gzip压缩application/vnd.oci.image.layer.nondistributable.v1.tar
: Image Layer, 非内容寻址管理application/vnd.oci.image.layer.nondistributable.v1.tar+gzip
: Image Layer, gzip压缩,非内容寻址管理
Media Type 的不一致
当获取块文件时,可以返回文件的Media Type,比如Http请求的返回头中设置Content-Type字段。镜像规范的实现也可能会有预期的Media Type。
- 当你没有预期的Media Type时,信任块文件返回的Media type类型。
- 当你预期的Media Type和返回一致时,是正常情况。
- 当你预期的Media Type和返回不一致时,你必须:
- 如果你的预期的Digest和返回块的Digest一致时,报一个警告。
- 如果你的预期的Digest和返回块的Digest不一致时,返回错误。
- 如果你没有预期的Digest,返回错误。
OCI Content Descriptor
- OCI 镜像由几部分组成,每个组件都是存储在一个目录结构中。
- 每个组件之间都是通过内容寻址的方式互相引用。
- Content Descriptor 描述了一个目标内容的位置。
- Content Descriptor 包含:内容的类型、内容的标识符、内容的大小。
- Content Descriptor 必须通过嵌入到其他格式中使用。
Content Descriptor 属性
mediaType
stringdigest
stringsize
int64urls
array of stringsannotations
string-string mapdata
string 保留字段
摘要和校验
digest属性是Descriptor的核心,扮演了内容的标识符的角色。digest使用了防碰撞的哈希算法唯一的标识了内容。如果标识符能够以安全的获取。那么就算内容通过了不安全的来源获取,也能独立计算出标识符对内容的正确性进行确认。
digest的格式要求与示例:(sha256已经是一个广泛使用的Hash算法)
digest := algorithm ":" hex
algorithm := /[a-z0-9_+.-]+/
hex := /[a-f0-9]+/
sha256:6c3c624b58dbbcd3c0dd82b4c53f04194d1247c6eebdaab7c610cf7d66709b3b
- 1
- 2
- 3
- 4
- 5
Content Descriptor 示例
这个 Content Descriptor 描述了一个Manifest
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"size": 7682,
"digest": "sha256:5b0bcabd1ed22e9fb1310cf6c2dec7cdef19f0ad69efa1f392e94a4333501270"
}
- 1
- 2
- 3
- 4
- 5
OCI 镜像布局规范
- OCI的镜像布局将内容寻址和位置寻址做了很明显的分割。
- 这个布局可以使用多种方式传输:归档文件、共享文件系统、网络传输等
详细内容
镜像布局有以下部分组成:
blobs
directory
- 内容寻址的块文件
- A blob has no schema and SHOULD be considered opaque ?
- 目录必须存在,但是可以为空
oci-layout
file
- 文件必须存在、必须是JSON格式
- 文件中必须包含一个
imageLayoutVersion
字段 - 文件中可以有其他字段作为扩展使用
index.json
file
- 文件必须存在、必须是JSON格式
- 文件中必须包含镜像Index的基本属性
示例
$ find . -type f
./index.json
./oci-layout
./blobs/sha256/3588d02542238316759cbf24502f4344ffcc8a60c803870022f335d1390c13b4
./blobs/sha256/4b0bc1c4050b03c95ef2a8e36e25feac42fd31283e8c30b3ee5df6b043155d3c
./blobs/sha256/7968321274dc6b6171697c33df7815310468e694ac5be0ec03ff053bb135e768
- 1
- 2
- 3
- 4
- 5
- 6
Blobs 文件夹
- blobs文件夹下的子文件夹是以Hash算法的名称来命名的,这些子文件夹下包含了真正的实体文件。
- 一个块被digest引用时(:,descriptor),这个块必须存放在
blobs/<alg>/<hex>
目录。 - blobs文件夹下面可能会存放很多已经没有任何引用的块文件。
- blobs文件夹下可以缺失一些被引用的块文件,只要被其他额外的块填满就可以了。
Blobs 示例
Image Index
$ cat ./blobs/sha256/9b97579de92b1c195b85bb42a11011378ee549b02d7fe9c17bf2a6b35d5cb079 | jq
{
"schemaVersion": 2,
"manifests": [
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"size": 7143,
"digest": "sha256:afff3924849e458c5ef237db5f89539274d5e609db5db935ed3959c90f1f2d51",
"platform": {
"architecture": "ppc64le",
"os": "linux"
}
},
...
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
Image Manifest
$ cat ./blobs/sha256/afff3924849e458c5ef237db5f89539274d5e609db5db935ed3959c90f1f2d51 | jq
{
"schemaVersion": 2,
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"size": 7023,
"digest": "sha256:5b0bcabd1ed22e9fb1310cf6c2dec7cdef19f0ad69efa1f392e94a4333501270"
},
"layers": [
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"size": 32654,
"digest": "sha256:e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f"
},
...
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
Image Config
$ cat ./blobs/sha256/5b0bcabd1ed22e9fb1310cf6c2dec7cdef19f0ad69efa1f392e94a4333501270 | jq
{
"architecture": "amd64",
"author": "Alyssa P. Hacker <alyspdev@example.com>",
"config": {
"Hostname": "8dfe43d80430",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": null,
"Image": "sha256:6986ae504bbf843512d680cc959484452034965db15f75ee8bdd1b107f61500b",
...
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
Image Layer Blob
$ cat ./blobs/sha256/e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f
[tar stream]
- 1
- 2
oci-layout 文件
在镜像规范中,这个文件特别简单,只有一个布局版本的字段。
oci-layout 示例
{
"imageLayoutVersion": "1.0.0"
}
- 1
- 2
- 3
index.json 文件
index.json文件相当于整个镜像的入口。从这个文件可以获取整个镜像依赖到的所有文件的信息。
每一个在manifests
字段中的descriptor
都指向一个 application/vnd.oci.image.index.v1+json 或 application/vnd.oci.image.manifest.v1+json 类型的文件。
一个通用的做法,org.opencontainers.image.ref.name注解被认为是镜像Tag的含义。表示镜像的不同版本。
index.json 示例
{
"schemaVersion": 2,
"manifests": [
{
"mediaType": "application/vnd.oci.image.index.v1+json",
"size": 7143,
"digest": "sha256:0228f90e926ba6b96e4f39cf294b2586d38fbb5a1e385c05cd1ee40ea54fe7fd",
"annotations": {
"org.opencontainers.image.ref.name": "stable-release"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"size": 7143,
"digest": "sha256:e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f",
"platform": {
"architecture": "ppc64le",
"os": "linux"
},
"annotations": {
"org.opencontainers.image.ref.name": "v1.0"
}
},
{
"mediaType": "application/xml",
"size": 7143,
"digest": "sha256:b3d63d132d21c3ff4c35a061adf23cf43da8ae054247e32faa95494d904a007e",
"annotations": {
"org.freedesktop.specifications.metainfo.version": "1.0",
"org.freedesktop.specifications.metainfo.type": "AppStream"
}
}
],
"annotations": {
"com.example.index.revision": "r124356"
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
OCI Image Manifest
官网中列举了Manifest的三大主要目标,但我觉得Manifest的主要任务就只有一个。
通过内容描述的方式,记录一个镜像的元信息,包括Image Config和Image Layers。
详细内容
- schemaVersion int
这个字段是必须的,以当前版本的规范你必须填2
(为了兼容老版本的Docker)。 - mediaType string
保留字段,用于标识当前文件是什么类型的。 - config descriptor
这个字段是必须的,用于标识镜像的配置文件的位置。
- mediaType string
配置文件的mediaType,必须使用这个application/vnd.oci.image.config.v1+json
- mediaType string
- layers array of descriptor
列表中的每一个成员都是一个镜像层,最底层的镜像在列表的第一项,其他各层按照堆叠顺序依次排列在后面。最终得到的文件系统应该和在一个空文件夹上堆叠各层得到的结果一样。用于堆叠的空文件夹的各种权限是不确定的。
- mediaType string
镜像层的mediaType,有比较多的选择:
- application/vnd.oci.image.layer.v1.tar
- application/vnd.oci.image.layer.v1.tar+gzip
- application/vnd.oci.image.layer.nondistributable.v1.tar
- application/vnd.oci.image.layer.nondistributable.v1.tar+gzip
- mediaType string
- annotations string-string map
注释,和其他定义一样。
示例
{
"schemaVersion": 2,
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"size": 7023,
"digest": "sha256:b5b2b2c507a0944348e0303114d8d93aaaa081732b86451d9bce1f432a537bc7"
},
"layers": [
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"size": 32654,
"digest": "sha256:e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f"
},
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"size": 16724,
"digest": "sha256:3c3a4604a545cdc127456d94e421cd355bca5b528f4a9c1905b15da2eb4a4c6b"
},
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"size": 73109,
"digest": "sha256:ec4b8955958665577945c89419d1af06b5f7636b4ac3da7f12184802ad867736"
}
],
"annotations": {
"com.example.key1": "value1",
"com.example.key2": "value2"
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
OCI Image Index
Image Index是一个更高层次的Manifest,一般在一个镜像需要提供多个平台支持时使用。
MediaType:application/vnd.oci.image.index.v1+json
详细内容
- schemaVersion int
这个字段是必须的,以当前版本的规范你必须填2
(为了兼容老版本的Docker)。 - mediaType string
保留字段,用于标识当前文件是什么类型的。 - manifests array of objects
这个字段是必须的,但是可能为空。他给出了对于特定平台的Manifests列表
- mediaType string
Manifests的mediaType,必须使用这个application/vnd.oci.image.manifest.v1+json
- platform object
这个字段是可选的,描述了Manifest中描述的镜像是运行在哪一个指定的平台。
- architecture string
这个字段是必须的,指定了CPU的架构类型。在运行时规范中会给出平台的相关帮助。 - os string
这个字段是必须的,指定了操作系统的类型。在运行时规范中会给出操作系统的相关帮助。 - os.version string
这个字段是可选的,指定操作系统的版本要求。 - os.features array of strings
这个字段是可选的,指定了一些对于系统的特殊要求。 - variant string
这个字段是可选的,指定了CPU的版本要求。 - features array of strings
这个字段是可选的,指定了一些对于CPU指令集的特殊要求。(比如sse4、aes) - annotations string-string map
注解
- architecture string
- mediaType string
示例
{
"schemaVersion": 2,
"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",
"os.features": [
"sse4"
]
}
}
],
"annotations": {
"com.example.key1": "value1",
"com.example.key2": "value2"
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
Image Layer
Annotations
对于大部分前文中描述的结构,基本都可以添加Annotations。对于Annotations的使用主要有以下一些内容。
使用规则
- Annotations必须是键值对,其中键必须是string类型的。
- 键必须唯一,最佳实践是使用命名空间,将其做区分。
- 值必须存在,但是可以是空字符串。
org.opencontainers
前缀的键是OCI规范的,不要随便用。org.opencontainers.image
前缀的键是OCI镜像规范的,不要随便用。- 使用镜像时,不要因为遇到了未知的注解,而直接抛出错误。
预定义的一些注解
org.opencontainers.image.created
镜像构建的日期 (string, RFC 3339).org.opencontainers.image.authors
镜像的负责人或组织 (string)org.opencontainers.image.homepage
镜像相关信息地址 (string, URL)org.opencontainers.image.documentation
镜像帮助文档地址 (string, URL)org.opencontainers.image.source
镜像源代码地址 (string, URL)org.opencontainers.image.ref.name
镜像名称(Tag) (string)
其他需要考虑的问题
可扩展性
为了保证可扩展性。使用该规范的实现,不能因为获取到了一些规范之外的属性,而产生错误或者是异常。
规范化
- OCI 镜像是基于内容寻址的。
- 内容寻址的一大好处就是可以共享重复的数据。
- 多个镜像依赖同一个层时,这个层只会存储一份。
- 使用不同的序列化算法时,语义上一样的层往往会得到不用的Hash值,这样的话这样语义上一样的层就会被存储两份。这两份是一样的。
- 为了保证高效存储,我们必须使用权威的序列化方式。
- 这样的话多个不同的该规范实现在推送时表现出来的行为将会是一致的。
- 许多组件都是JSON格式的,这里也应该使用权威的序列化方式。
更多推荐
所有评论(0)