OCI 与容器镜像构建
大家好,我是张晋涛。
这篇文章中我将介绍 OCI 及容器镜像相关的内容,欢迎留言讨论。
OCI 的前世今生
2013 年 3 月 dotCloud 公司在 PyCon 上进行了 Docker 的首次展示,随后宣布开源。自此 Docker 开始被众人知晓,随后掀起了一股容器化的热潮。
在 2014 年 6 月 Docker 1.0 正式发布,有近 460 位贡献者和超过 8700 次提交,这也标志着 Docker 达到了生产可用的状态。
在当时,提到容器化第一想法就是用 Docker 。而当时 Docker 的实现或者说发展方向主要是由 Docker Inc. 公司控制的,并没有一个统一的工业标准。这对于一些头部公司而言,显然是不能接受的,没有统一的工业标准意味着如果选择了使用 Docker 的容器化技术,便会被 Docker Inc. 公司所绑定;加上随着 Docker 软件的升级,某些功能或者特性必然会进行变动,没人能保证不发生破坏性变更。
所以,为了推进容器化技术的工业标准化,2015 年 6 月在 DockerCon 上 Linux 基金会与 Google,华为,惠普,IBM,Docker,Red Hat,VMware 等公司共同宣布成立开放容器项目(OCP),后更名为 OCI。它的主要目标便是 建立容器格式和运行时的工业开放通用标准。
发展至今, OCI 制定的主要标准有三个分别是 runtime-spec
、image-spec
和 distribution-spec
这三个标准分别定义了容器运行时,容器镜像还有分发的规范,后面会展开介绍。
为了支持 OCI 容器运行时标准的推进,Docker 公司起草了镜像格式和运行时规范的草案,并将 Docker 项目的相关实现捐献给了 OCI 作为容器运行时的基础实现,现在项目名为 runc
。
后来 Docker 将其容器运行时独立成了一个项目,名为 containerd
并将此项目捐献给了 CNCF ,现在已经是 CNCF 毕业项目了。
OCI image vs Docker image
OCI 的建立推动了容器技术的工业标准化,但是否此标准就是唯一呢?其实不然。在成立 OCI 并制定 image-spec
标准的时候 Docker 已经空前繁荣,并得到了广泛的应用。
由于标准只定义了最基本的内容,想要将 Docker 的实现全部按照标准进行改造的话,会对 Docker 造成破坏性变更,也不利于 Docker 功能的迭代。
所以,Docker 为了支持 OCI 标准的普及,已经推进了 registry 对 OCI 镜像的支持,现在也正在给 Docker 自身增加适配中,目标是让 Docker 支持两种镜像格式,分别是符合 Docker 标准的镜像和符合 OCI 标准的镜像。
那这两者有什么异同呢?我们来逐步看下。
Docker Image 和 OCI Image 的区别和联系
在我以前的文章中我们已经详细的从根本上介绍了 Docker image 是什么,这里我们就快速的介绍下。
每个 Docker 镜像都是由一系列的配置清单和相应的层进行组织的。每个层一般都是 tar 格式的归档,配置清单中描述了对应的层应该按何种顺序进行组织,以及镜像的一些元属性。比如镜像所支持的架构,例如 amd64
之类的,还有 ENV 等提前配置好的一些参数等。
当然,在 Docker Image 中也包含着构建镜像时候所用的 Docker 版本 docker_version
以及构建镜像的历史记录 history
等信息。所以你在 DockerHub
或者其他的镜像仓库上可以看到构建镜像所用的 Docker 版本, 或者可通过 docker history <IMAGE>
的方式来查看构建历史。
那么 OCI Image 是什么呢?首先我们需要有一个 OCI Image 才好探究它到底是什么。
这里介绍一个工具 skopeo 可以很方便的从镜像仓库或者本地 Docker daemon 甚至是通过 docker save
保存的 Docker Image tar 文件转换为 OCI Image 。
关于 skopeo 的安装过程就不再赘述了,参考项目主页的文档说明即可。这里直接开始使用。
我们使用 debian
的镜像为例。
(MoeLove) ➜ skopeo copy docker://debian:stretch oci:debian:stretch
Getting image source signatures
Copying blob a4d8138d0f6b done
Copying config 45f82268e3 done
Writing manifest to image destination
Storing signatures
通过上面的命令便会得到一个 OCI Image 了, 我们看下它的目录结构。
(MoeLove) ➜ tree debian
debian
├── blobs
│ └── sha256
│ ├── 0043cd2a654fe86258f43f5b1dbbb4e6c582cc4bb6e505e9c5171c124150d155
│ ├── 45f82268e32180cb1839f90467d9b8a8258953d68b7221199976653308d92ef5
│ └── a4d8138d0f6b5a441aaa533faf5fe0c3996a6ca42643c46f4402c7e8bda53742
├── index.json
└── oci-layout
2 directories, 5 files
是不是有种似曾相识的感觉?没错 OCI Image 的规范是在 Docker Image 的基础上建立的,所以大致看起来差异不是特别大。我们看看其中具体的内容。
oci-layout
这个文件是 OCI Image 的布局文件,也是用于说明它所使用或者遵循的镜像规范。
(MoeLove) ➜ debian cat oci-layout| jq
{
"imageLayoutVersion": "1.0.0"
}
可以看到此处的内容写的是 1.0.0
这便说明该镜像遵循 OCI 1.0.0 版本的布局规范。
index.json
index.json
文件中的 manifest
字段类似于 Docker Image 中的 manifest.json
作为 OCI Image 的顶级配置, 也是镜像的一个入口配置。
(MoeLove) ➜ debian cat index.json | jq
{
"schemaVersion": 2,
"manifests": [
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:0043cd2a654fe86258f43f5b1dbbb4e6c582cc4bb6e505e9c5171c124150d155",
"size": 349,
"annotations": {
"org.opencontainers.image.ref.name": "stretch"
},
"platform": {
"architecture": "amd64",
"os": "linux"
}
}
]
}
从它的内容可以看到它其中的 mediaType
字段与 Docker Image 中的类型形式相同,但是将 docker
都换成了 oci
。从这个配置文件,我们可以找到第一个 blob 是 sha256:0043cd2a654fe86258f43f5b1dbbb4e6c582cc4bb6e505e9c5171c124150d155
我们看看它的内容。
(MoeLove) ➜ debian cat blobs/sha256/0043cd2a654fe86258f43f5b1dbbb4e6c582cc4bb6e505e9c5171c124150d155 | jq
{
"schemaVersion": 2,
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"digest": "sha256:45f82268e32180cb1839f90467d9b8a8258953d68b7221199976653308d92ef5",
"size": 579
},
"layers": [
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"digest": "sha256:a4d8138d0f6b5a441aaa533faf5fe0c3996a6ca42643c46f4402c7e8bda53742",
"size": 45337510
}
]
}
这个入口文件描述了 OCI 镜像的实际配置和其中的 Layer 配置。如果有多层那 layers
也会相应增加。
注意:layers 中 mediaType
使用了 application/vnd.oci.image.layer.v1.tar+gzip
说明数据内容是经过 gzip 压缩的 如果有兴趣你可以将它用 tar 解压一下,你会发现很有趣的内容。
“这里先将结果说出来,解压后你会得到一个
”rootfs
这与 Docker Image 是类似的。
小结
我们通过 skopeo 工具,从本地的 Docker daemon 中由 debian 的 Docker Image 得到了 OCI Image,并分析了它其中的内容。
最主要的区别在于它们的目录结构不完全相同,配置信息尤其是 mediaType
的规范是不相同的。
而它们的联系也在于此,OCI Image 的规范是由 Docker Image 的规范修改而来的,所以类似它们的 blob 的组织形式大致是相同的,配置文件中很多的参数也相似。
另外,我们也可以很容易的得到另一个结论,那便是我们可以很方便的将 Docker Image 转换为 OCI Image 。
OCI image 和 Docker image 的转换
上面我们已经看到,使用 skopeo 工具,可以将 Docker Image 转换为 OCI Image ,当然它也可以将 OCI Image 转换为 Docker Image 。下面给出了方法:
# 从 DockerHub 将 debian 的 Docker Image 拉取并转换为 OCI Image
(MoeLove) ➜ skopeo copy docker://debian:stretch oci:debian:stretch
Getting image source signatures
Copying blob a4d8138d0f6b done
Copying config 45f82268e3 done
Writing manifest to image destination
Storing signatures
# 将当前目录下的 debian 的 OCI Image 转换为 Docker Image 并存储到本地 docker daemon 中
(MoeLove) ➜ skopeo copy oci:debian:stretch docker-daemon:local/debian:oci
Getting image source signatures
Copying blob 0e350e141713 done
Copying config aae58a37cf done
Writing manifest to image destination
Storing signatures
# 验证
(MoeLove) ➜ oci docker images local/debian
REPOSITORY TAG IMAGE ID CREATED SIZE
local/debian oci ac6bcf605d82 6 months ago 101MB
镜像构建工具
在 CI/CD 环境中,虽然我们可以使用 DinD (Docker in Docker) 的方式启动一个 docker daemon 或者使用挂载的方式,将外部的 /var/run/docker.sock
挂载进容器内部,亦或者将 Docker API 使用 HTTP 的方式暴露出来,直接使用该地址进行构建。
但这些方式你是否会觉得比较重?是否有考虑安全问题,或者压力及负载的问题?
这里的压力及负载主要是指当所有的任务都共用同一个 docker daemon 提供服务的话,对该 docker daemon 造成的压力。
这里我们来介绍一些其他的镜像构建工具,使用这些工具可以让你在无 Docker 的环境下构建出镜像并上传至 Docker 镜像仓库中。
到目前为止,我们可以有很多种选择:
-
BuildKit -
img -
orca-build -
umoci -
buildah -
kaniko -
FTL -
Bazel rules_docker
这些工具侧重点各有不同,当然也不仅有上面列到的这些工具,只是这些工具比较典型罢了。
通常情况下,在网络上比较容易见到宣传为下一代镜像构建工具的是 buildah
,最主要原因是因为它可以直接构建 OCI 标准的镜像或 Docker 镜像,也可以直接使用 Dockerfile
。并且它还可以 pull
/push
镜像,可以说在镜像构建方面与 Docker 是完全兼容,甚至可以说它在构建镜像方面可以作为 Docker 的替代品了。
并且 buildah
构建镜像的时候不需要任何 root
权限,也不依赖 Docker, 它使用了简单的 fork-exec
模型,同时它也可以作为一个库包含在其他的工具中。它的最终目标便是提供一个更低层次的核心工具集,来完成构建镜像相关的事情。
说完这个典型的替代品,我们再来说下 BuildKit
和 img
, img
这个工具是构建在 BuildKit
之上的,所以有很多相似性。它们使用非 root 用户来构建镜像。当然 BuildKit
我在之前的文章中详细介绍过了,它是 Docker 内置的下一代构建工具,独立使用也是可以的。称它为“下一代镜像构建工具” 也并不为过。
kaniko
是 Google 推出的,它主要的宣传语为 “在 Kubernetes 中构建容器镜像” 实际上无论是在 K8S 集群中或者在容器中它都是可以工作的。它也可以使用 Dockerfile
构建镜像。当然还有很重要的一点,它所有的构建命令都是运行在用户态的,并且也可以很好的与 Kubernetes 结合,在云原生时代下,它也占据了一定的优势。
以上工具都只是大致介绍了下,如果对它们感兴趣,可直接进入项目主页查看 README.md
基础使用都有比较详细的说明,这里不再进行赘述了。
总结
本篇为大家介绍了 OCI 的前世今生,以及 OCI Image 的规范和特点,另外也介绍了一个可用于在 OCI Image 和 Docker Image 之间镜像转换的工具 skopeo
。另外介绍了一些可用于在 CI 环境或其他有特定场景环境下替代 Docker build 的工具,请大家按实际需求进行选择。
欢迎订阅我的文章公众号【MoeLove】
本文分享自微信公众号 - MoeLove(TheMoeLove)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
万字长文|StreamNative CEO 郭斯杰:关于开源商业化的新主张
北京时间 10 月 12 日,云原生批流融合数据平台 StreamNative 获得 2300 万美元 A 轮融资,本轮融资由沙特阿美旗下多元化风投基金 Prosperity7 Ventures 与华泰证券旗下另类投资子公司华泰创新联合领投,老股东红杉中国、源码资本继续加码。 StreamNative 于 2020 年 8 月完成数百万美元 Pre-A 轮融资,源码资本领投、红杉中国种子基金跟投;2019 年团队创立初期获得红杉中国种子基金天使轮投资。 近日,StreamNative 联合创始人郭斯杰接受 InfoQ 采访,与 InfoQ 中国的掌舵者 Kevin 进行深度对话,为 InfoQ 的开发者们分享了 StreamNative 创业路上的艰辛、踩坑、梦想,以及对于开源项目、开源社区及开源商业化等方向的看法。 以下为郭斯杰采访文字实录,略有改动。 关于 Pulsar 的诞生 我叫郭斯杰,是 StreamNative 的联合创始人兼 CEO,是两个 Apache 软件基金会顶级项目 Pulsar 和 BookKeeper 的 PMC 成员,PMC 全称叫 Project Mana...
- 下一篇
GitOps 应用实践系列 - Flux CD 及其核心组件
大家好,我是张晋涛。 经过前面三篇文章,不仅为大家介绍了什么是 GitOps 也介绍了如何利用 Argo CD 来实施 GitOps。本篇我来为你介绍另一个可用于实施 GitOps 的工具:Flux CD 。 Flux CD img Flux 是一组可支持实现 GitOps 的工具,用于使 Kubernetes 集群与配置源(如 Git 仓库)保持同步,并在有代码更新后自动同步配置,面向 Kubernetes 的持续渐进式交付解决方案。 img Flux CD 的发展历史 2016 年 10 月 28 日,Flux single-user service 版本发布。 它奠定了 flux 的两个基调: 集中式运行的服务 以守护进程的方式,在自动模式下运行在 k8s 集群中 2016 年 12 月 15 日,发布《使用 Weave Flux 持续交付》,构建了将 CI 与持续部署 (CD) 联系起来的 Flux。 2017 年 8 月 22 日,v1.0.0 版本正式发布。 自 v1.0.0 开始,Flux 致力于将集群与存储在 Git 中的配置同步,并在新版本准备好部署时自动升级镜像。(...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS8编译安装MySQL8.0.19
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Red5直播服务器,属于Java语言的直播服务器
- CentOS7安装Docker,走上虚拟化容器引擎之路
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- CentOS6,7,8上安装Nginx,支持https2.0的开启