大家好,我是张锦涛。在这篇文章中,我将介绍与OCI和Docker镜像相关的内容。欢迎留言讨论。OCI的前世今生2013年3月,dotCloud在PyCon上首次展示了Docker,随后宣布开源。从此,Docker为大家所熟知,继而掀起了一股容器化浪潮。Docker1.0于2014年6月正式发布,拥有近460名贡献者和超过8,700次提交,标志着Docker的生产就绪状态。当时容器化首先想到的就是用Docker。当时Docker的实现或发展方向主要由DockerInc.掌控,没有统一的行业标准。这对于一些龙头企业来说,显然是无法接受的。缺乏统一的行业标准,意味着如果选择使用Docker的容器化技术,就会受到DockerInc.的约束;升级时,某些功能或特性难免会发生变化,谁也不能保证不会发生破坏性的变化。因此,为推动容器化技术的产业标准化,在2015年6月的DockerCon上,Linux基金会、谷歌、华为、HP、IBM、Docker、RedHat、VMware等公司联合宣布成立OpenContainerProject(OCP),后来更名为OCI。它的主要目标是为容器格式和运行时建立一个全行业开放的通用标准。到目前为止,OCI已经制定了三个主要标准:runtime-spec、image-spec和distribution-spec。这三个标准分别定义了容器运行时、容器镜像和分发规范,后面会介绍。为了支持OCI容器运行时标准的推进,Docker起草了镜像格式和运行时规范草案,并将Docker项目的相关实现捐赠给了OCI作为容器运行时的基础实现。该项目现在称为runc。后来Docker把它的容器运行时分离成一个叫containerd的项目,把这个项目捐给了CNCF,现在已经是CNCF的毕业项目了。OCI镜像vsDocker镜像OCI的建立推动了容器技术的产业标准化,但这个标准是唯一的吗?其实并不是。当OCI成立,image-spec标准确立的时候,Docker已经兴盛,应用广泛。由于标准只定义了最基本的内容,如果想把Docker的所有实现都按照标准进行改造,将会对Docker造成破坏性的改变,不利于Docker功能的迭代。因此,为了支持OCI标准的普及,Docker推动了registry对OCI镜像的支持,现在正在对Docker自身进行适配。目标是让Docker支持两种镜像格式,即符合Docker标准的镜像和符合Docker标准的镜像。OCI标准的镜像。那么两者有什么相同点和不同点呢?让我们一步步来看。DockerImage和OCIImage的区别和联系在我之前的文章中,我们已经详细介绍了DockerImage从根本上是什么。在这里,我们将进行快速介绍。每个Docker镜像都由一系列配置清单和相应的层组成。每一层一般是一个tar格式的归档文件,配置列表描述了对应层的组织顺序,以及镜像的一些元属性。比如镜像支持的架构,比如amd64,还有一些提前配置的参数,比如ENV。当然,DockerImage中还包含了构建镜像所用的Docker版本docker_version、构建镜像的历史等信息。所以可以在DockerHub或者其他镜像仓库上看到构建镜像使用的Docker版本,也可以通过dockerhistory查看构建历史。那么什么是OCIImage呢?首先,我们需要有一个OCIImage,看看它是什么。这里有一个工具,skopeo,它可以很容易地从镜像仓库或本地Docker守护进程甚至是通过dockersave保存的DockerImagetar文件转换为OCIImage。skopeo的安装过程我就不赘述了,直接参考项目首页的文档即可。从这里开始。我们以debian镜像为例。(MoeLove)?skopeocopydocker://debian:stretchoci:debian:stretch获取镜像源签名Copyingbloba4d8138d0f6bdoneCopyingconfig45f82268e3doneWritingmanifesttoimagedestinationStoringsignatures通过以上命令,我们将得到一个OCIImage。目录结构。(MoeLove)?treedebiandebian├──blobs│??└──sha256│??├──0043cd2a654fe86258f43f5b1dbbb4e6c582cc4bb6e505e9c5171c124150d155│??├──45f82268e32180cb1839f90467d9b8a8258953d68b7221199976653308d92ef5│??└──a4d8138d0f6b5a441aaa533faf5fe0c3996a6ca42643c46f4402c7e8bda53742├──index.json└──oci-layout2directories,5files是不是有似曾相识的感觉?没错,OCIImage的规范是基于DockerImage的,所以看起来差别不是特别大。我们来看看具体的内容。oci-layout文件是OCIImage的布局文件,也用于描述其使用或遵循的图像规范。(MoeLove)?debiancatoci-layout|jq{"imageLayoutVersion":"1.0.0"}可以看到这里的内容是1.0.0,也就是说图片遵循OCI1.0.0版本的布局规范。index.jsonindex.json文件中的manifest字段类似于DockerImage中的manifest.json作为OCIImage的顶层配置,也是镜像的入口配置。(MoeLove)?debiancatindex.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",linux"}}]}从它的内容可以看出mediaType字段与DockerImage中的type相同,只是docker换成了oci,从这个配置文件中我们可以发现第一个blob是sha256:0043cd2a654fe86258f43f5b1dbbb4e6c582cc4bb6e505e9c5171c124150d155,我们看一下它的内容。(萌爱)?debiancatblobs/sha256/0043cd2a654fe86258f43f5b1dbbb4e6c582cc4bb6e505e9c5171c124150d155|jq{“schemaVersion”:2,“config”:{“mediaType”:“application/vnd.sha256:45f82268e32180cb1839f90467d9b8a8258953d68b7221199976653308d92ef5”,“size”:579},“layers”:[{“mediaType/vnd”:“application.image.layer.v1.tar+gzip","digest":"sha256:a4d8138d0f6b5a441aaa533faf5fe0c3996a6ca42643c46f4402c7e8bda53742","size":45337510}]}这个入口文件描述了OCI镜像的实际配置以及里面的Layer配置。如果有多层,层数也会相应增加。注意:layers中的mediaType使用application/vnd.oci.image.layer.v1.tar+gzip,表示数据内容是经过gzip压缩的。有兴趣的可以用tar解压,会发现很有意思的内容。首先是结果。解压后会得到一个rootfs,类似于DockerImage。总结我们通过skopeo工具从本地Docker守护进程中获取debianDockerImage中的OCIImage,并对其内容进行分析。主要区别在于它们的目录结构并不完全相同,配置信息,尤其是mediaType的规范也不一样。这就是它们的连接点。OCIImage的规范是从DockerImage的规范修改而来的,所以与其类似的blob的组织形式大致相同,配置文件中的很多参数也类似。此外,我们还可以很容易地得出另一个结论,那就是我们可以很方便地将DockerImage转换为OCIImage。OCI镜像与Docker镜像的转换我们在上面已经看到,使用skopeo工具可以将DockerImage转换为OCIImage,当然也可以将OCIImage转换为DockerImage。方法如下:#Pullandconvertdebian'sDockerImagefromDockerHubtoOCIImage(MoeLove)?skopeocopydocker://debian:stretchoci:debian:stretchGettingimagesourcesignaturesCopyingbloba4d8138d0f6bdoneCopyingconfig45f82268e3doneWritingmantoimagedestinationStoringsignatures#将当前目录下的debianOCIImage转换为DockerImage并存储在本地dockerdaemon(MoeLove)?skopeocopyoci:debian:stretchdocker-daemon:local/debian:ociGettingimagesourcesignaturesCopyingblob0e350e141713doneCopyingconfigaae58a37cfdoneWritingmanifesttoimagedestinationStoringsignatures#Verify(MoeLove)?ocidockerimageslocal/debianREPOSITORYTAGIMAGEIDCREATEDSIZElocal/debianociac6bcf605d826monthsago尽管我们可以在CI/Docker中使用Din101MB图像构建工具(在Docker中)来启动一个dockerdaemon或者使用挂载方式将外部的/var/run/docker.sock挂载到容器中,或者使用HTTP暴露DockerAPI直接使用这个地址来构建。但是你在这些方面感觉更重了吗?您是否考虑过安全问题或压力和负载问题?这里的压力和负载主要是指当所有任务共享同一个dockerdaemon提供服务时对dockerdaemon的压力。这里我们介绍一些其他的镜像构建工具,可以让你在无Docker环境下构建镜像,并上传到Docker镜像仓库。到目前为止,我们有很多选择:BuildKitimgorca-buildumocibuildahkanikoFTLBazelrules_docker这些工具各有侧重,当然不止上面列举的这些工具,这些工具比较典型。通常,在网上更容易看到buildah是下一代镜像构建工具。主要是它可以直接构建OCI标准镜像或者Docker镜像,也可以直接使用Dockerfile。它还可以拉/推图像。可以说在镜像构建方面完全兼容Docker,在镜像构建方面甚至可以替代Docker。而且buildah在构建镜像时不需要任何root权限,不依赖Docker。它使用简单的fork-exec模型,也可以作为库包含在其他工具中。它的最终目标是提供一个更底层的核心工具集来完成构建镜像相关的事情。说完这个典型的替代品,再来说说BuildKit和img。img工具建立在BuildKit之上,因此有很多相似之处。他们使用非root用户来构建图像。当然,我在之前的文章中已经详细介绍了BuildKit。它是Docker内置的下一代构建工具,可以独立使用。称其为“下一代图像构建工具”一点也不为过。Kaniko是由谷歌推出的。它的主要口号是“在Kubernetes中构建容器镜像”。其实无论是在K8S集群还是在容器中都可以工作。它还可以使用Dockerfile构建图像。当然,还有很重要的一点。它所有的构建命令都运行在用户模式下,也可以很好地与Kubernetes集成。在云原生时代,它也有一定的优势。以上工具只是一个大概的介绍。如果你对它们感兴趣,可以直接进入项目主页查看README.md。基本使用还有更详细的说明,这里不再赘述。小结本文介绍了OCI的前世今生,以及OCIImage的规范和特点,同时介绍了skopeo这个可以用于OCIImage和DockerImage镜像转换的工具。此外,还介绍了一些在CI环境或其他特定场景下可用于替代Docker构建的工具。请根据您的实际需要选择。欢迎订阅我的文章公众号【MoeLove】