searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

容器OCI规范介绍

2023-07-19 02:40:07
404
0

OCI(Open Container Initiative)是一组围绕容器技术的开放标准和规范,主要定义了容器的生命周期管理规范。

OCI 的实现者通常被称为“低级容器运行时”,例如 runC。低级运行时的主要功能是按照给定的容器文件系统和 JSON 配置文件,创建容器,并管理容器的生命周期。

创建容器需要做一些 namespaces 和 cgroups 的配置,以及挂载 root 文件系统等操作,这些操作其实已经有了标准的规范,那就是 OCI(开放容器标准),runc 就是它的一个参考实现(Docker 被逼无耐将 libcontainer 捐献出来改名为 runc 的),这个标准其实就是一个文档,主要规定了容器镜像的结构、以及容器需要接收哪些操作指令,比如 create、start、stop、delete 等这些命令。runc 就可以按照这个 OCI 文档来创建一个符合规范的容器,既然是标准肯定就有其他 OCI 实现,比如 Kata、gVisor 这些容器运行时都是符合 OCI 标准的。

OCI是在防止容器技术分裂的背景下提出的,制定容器镜像格式和容器运行时的正式规范(OCI Specifications),其内容主要包括OCI Runtime Spec(容器运行时规范)、OCI Image Spec(镜像格式规范)、OCI Distribution Spec(镜像分发规范)。

其中,我们熟知的runc就是Runtime Spec的一种参考实现。最早是从 Docker的 libcontainer中迁移而来的,后由Docker捐献给OCI。Docker容器也是基于runc创建的。

这样容器运行时可以从层级上进行如下划分:

  • low-level runtime(即OCI 运行时):指的是仅关注运行容器的容器运行时,调用操作系统,使用 namespace 和 cgroup 实现资源隔离和限制。例如,runc、rkt等。
  • high-level runtime:相较于low-level runtimes位于堆栈的上层,负责传输和管理容器镜像,解压镜像,并传递给low-level runtimes来运行容器。例如 containerd、cri-o等。

 

1.1 总述

最早的容器格运行时是lxc,docker最早让容器火起来,docker最开始用lxc,觉得隔离性差,开发libcontainer,最终形成runc。所以说,runc是docker的独生子。

K8S时,发现市面上docker挺火,因此就用docker。docker越做越重,CoreOS做了rkt容器格式。rkt与K8S协同工作比较好。容器运行时格式有点多了,linux基金会主导的开源项目说:我们要做一个container runtime标准。叫OCI。以后容器运行时要符合这个标准。docker的独生子runc在第一时间符合了OCI标准。

K8S为了与容器运行时解耦(主要是docker),提出了CRI(Container Runtime Interface)标准。它是一组与K8S与container runtime进行交互的接口。所以说,CRI和OCI并不冲突:K8S定义的是它调用容器运行时的标准接口,OCI定义的是容器运行时本身的标准。

OCI关于容器运行时的标准提出来以后,红帽想可以专门为K8S做一个轻量级的容器运行时。红帽自然会考虑到它自己全力投入的K8S发布的CRI标准(K8S红帽代码贡献第二),因此决定重用了runc等基本组件来启动容器, 并实现了一个最小的 CRI 接口。它叫CRI-O。所以说,CRI-O是CRI的一种标准实现。

当Red Hat正在开发其CRI-O,Docker也在研究CRI标准,这导致创建了另一个名为containerd的运行时(实际上是从docker engine剥离出来的)。所以新版本的docker会多一层containerd。kubernetes将containerd接入到cri的标准中。即cri-containerd。

1.2 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全称是Open Container Initiative,定义得是容器运行时的标准。这个标准,使用Linux的cgroup和namespace等技术,和docker所使用的技术没什么两样。docker只不过是OCI的一个实现而已,就像gVisor(runsc)所实现的一样。

OCI代表Open Container Initiative(开放容器倡议),它标准化了容器工具和技术之间的许多接口。它们维护了包装容器映像(OCI映像规范)和运行容器(OCI运行时规范)的标准规范。它们还以runc的形式维护运行时规范的实际实现,它是containerd和CRI-O的底层默认运行时。CRI构建在这些低层规范之上,为管理容器提供端到端标准。

发展至今, OCI 制定的主要标准有三个分别是 runtime-spec 、image-spec 和 distribution-spec 这三个标准分别定义了容器运行时,容器镜像还有分发的规范。

其实,现阶段,docker只是众多容器技术中的其中一种。它有三个主要的概念:

  • 镜像:代表了最终的软件包,不可变的软件载体。相当于安装文件
  • 容器:镜像的运行时,实际运行的实例,具有明确的进程号
  • 仓库:存放镜像的仓库,可以进行统一的版本管理和权限管理

 

为了支持 OCI 容器运行时标准的推进,Docker 公司起草了镜像格式和运行时规范的草案,并将 Docker 项目的相关实现捐献给了 OCI 作为容器运行时的基础实现,现在项目名为 runc 。后来 Docker 将其容器运行时独立成了一个项目,名为 containerd 并将此项目捐献给了 CNCF ,现在已经是 CNCF 毕业项目了。

Docker公司其实是捐献了Containerd和runC。这俩到底是啥东西。简单的说,runC是OCI标准的实现,也叫OCI运行时,是真正负责操作容器的。Containerd对外提供接口,管理、控制着runC。

docker是运行时和一堆开发工具集合的统称。docker-cli就不必多说了,就是一堆命令行的集合,我们主要看一下运行时:

 

  • docker:我们平常操作docker,使用的就是docker命令,它就是我们所说的命令行接口,相当于一个客户端。它将指令发送到dockerd
  • dockerd:docker的服务端。比如我们在Linux上安装docker,就要启动一个常驻进程,才能管理所有的docker进程.
  • containerd:这个组件,是从11版本才有的,是从dockerd里拆出来的,是容器标准化后的产物,它遵循的是OCI标准。containerd功能齐全,换句话说,你的服务器上可以没有dockerd,只需要containerd就能运行你的容器
  • runc:容器运行时组件,是一个标准的OCI容器实现运行时,可用来直接创建和运行容器。runC是一个轻量级的工具,用来运行容器的,我们可以不用通过docker引擎,直接运行容器。可以看到containerd和runc都是OCI的实现,区别是前者是管理工具,后者是运行容器
  • containerd-shim:垫片的意思,containerd-shim是一个真实运行容器的载体,为了能够支持多种OCI Runtime,containerd内部使用containerd-shim将containerd与真正的容器运行时进行解耦,每启动一个容器都会起一个新的containerd-shim的进程。它通常指定三个因素:容器ID、bundle目录(对应某个容器生成的目录,一般位于:/var/run/docker/containerd/containerID)
  • ctr:也叫做containerd-ctr,是containerd的客户端。此外,containerd 还实现了更丰富的容器接口,可以使用 ctr 工具来调用这些丰富的容器运行时接口,而不只是 CRI 接口。例如:
    • crictl:一个类似 docker 的命令行工具,用来操作 CRI 接口。
    • critest:验证 CRI 接口是否是符合预期。
    • 性能工具:测试接口性能。

 

docker本身而言,包括docker client和dockerd,是一个客户端工具,用来把用户的请求发送给docker daemon(dockerd)。

dockerd:dockerd是对容器相关操作的最上层封装,直接面向操作用户。Docker daemon,一般也会被称为docker engine。dockerd启动时会启动containerd 子进程。

containerd囊括了单机运行一个容器时所需要的一切,为了能够支持多种OCI Runtime,containerd 内部使用containerd-shim,每启动一个容器都会创建一个新的containerd-shim进程,指定容器ID,Bundle目录,运行时的二进制(比如runc)。

docker镜像和containerd镜像通用,但组织方式和存放目录不同,导致docker与ctr命令不通用,各自管理自己的镜像和容器。此外k8s还有客户端命令crictl,用法与docker基本相同,可crictl -h查看用法。

从 Docker 1.11 版本开始,Docker 容器运行就不是简单通过 Docker Daemon 来启动了,而是通过集成 containerd、runc 等多个组件来完成的。虽然 Docker Daemon 守护进程模块在不停的重构,但是基本功能和定位没有太大的变化,一直都是 CS 架构,守护进程负责和 Docker Client 端交互,并管理 Docker 镜像和容器。现在的架构中组件 containerd 就会负责集群节点上容器的生命周期管理,并向上为 Docker Daemon 提供 gRPC 接口。

当我们要创建一个容器的时候,现在 Docker Daemon 并不能直接帮我们创建了,而是请求 containerd 来创建一个容器,containerd 收到请求后,也并不会直接去操作容器,而是创建一个叫做 containerd-shim 的进程,让这个进程去操作容器,我们指定容器进程是需要一个父进程来做状态收集、维持 stdin 等 fd 打开等工作的,假如这个父进程就是 containerd,那如果 containerd 挂掉的话,整个宿主机上所有的容器都得退出了,而引入 containerd-shim 这个垫片就可以来规避这个问题了。

然后创建容器需要做一些 namespaces 和 cgroups 的配置,以及挂载 root 文件系统等操作,这些操作其实已经有了标准的规范,那就是 OCI(开放容器标准),runc 就是它的一个参考实现(Docker 被逼无耐将 libcontainer 捐献出来改名为 runc 的),这个标准其实就是一个文档,主要规定了容器镜像的结构、以及容器需要接收哪些操作指令,比如 create、start、stop、delete 等这些命令。runc 就可以按照这个 OCI 文档来创建一个符合规范的容器,既然是标准肯定就有其他 OCI 实现,比如 Kata、gVisor 这些容器运行时都是符合 OCI 标准的。

所以真正启动容器是通过 containerd-shim 去调用 runc 来启动容器的,runc 启动完容器后本身会直接退出,containerd-shim 则会成为容器进程的父进程, 负责收集容器进程的状态, 上报给 containerd, 并在容器中 pid 为 1 的进程退出后接管容器中的子进程进行清理, 确保不会出现僵尸进程。

而 Docker 将容器操作都迁移到 containerd 中去是因为当前做 Swarm,想要进军 PaaS 市场,做了这个架构切分,让 Docker Daemon 专门去负责上层的封装编排,当然后面的结果我们知道 Swarm 在 Kubernetes 面前是惨败,然后 Docker 公司就把 containerd 项目捐献给了 CNCF 基金会,这个也是现在的 Docker 架构。

0条评论
作者已关闭评论
刘****宽
3文章数
0粉丝数
刘****宽
3 文章 | 0 粉丝
刘****宽
3文章数
0粉丝数
刘****宽
3 文章 | 0 粉丝
原创

容器OCI规范介绍

2023-07-19 02:40:07
404
0

OCI(Open Container Initiative)是一组围绕容器技术的开放标准和规范,主要定义了容器的生命周期管理规范。

OCI 的实现者通常被称为“低级容器运行时”,例如 runC。低级运行时的主要功能是按照给定的容器文件系统和 JSON 配置文件,创建容器,并管理容器的生命周期。

创建容器需要做一些 namespaces 和 cgroups 的配置,以及挂载 root 文件系统等操作,这些操作其实已经有了标准的规范,那就是 OCI(开放容器标准),runc 就是它的一个参考实现(Docker 被逼无耐将 libcontainer 捐献出来改名为 runc 的),这个标准其实就是一个文档,主要规定了容器镜像的结构、以及容器需要接收哪些操作指令,比如 create、start、stop、delete 等这些命令。runc 就可以按照这个 OCI 文档来创建一个符合规范的容器,既然是标准肯定就有其他 OCI 实现,比如 Kata、gVisor 这些容器运行时都是符合 OCI 标准的。

OCI是在防止容器技术分裂的背景下提出的,制定容器镜像格式和容器运行时的正式规范(OCI Specifications),其内容主要包括OCI Runtime Spec(容器运行时规范)、OCI Image Spec(镜像格式规范)、OCI Distribution Spec(镜像分发规范)。

其中,我们熟知的runc就是Runtime Spec的一种参考实现。最早是从 Docker的 libcontainer中迁移而来的,后由Docker捐献给OCI。Docker容器也是基于runc创建的。

这样容器运行时可以从层级上进行如下划分:

  • low-level runtime(即OCI 运行时):指的是仅关注运行容器的容器运行时,调用操作系统,使用 namespace 和 cgroup 实现资源隔离和限制。例如,runc、rkt等。
  • high-level runtime:相较于low-level runtimes位于堆栈的上层,负责传输和管理容器镜像,解压镜像,并传递给low-level runtimes来运行容器。例如 containerd、cri-o等。

 

1.1 总述

最早的容器格运行时是lxc,docker最早让容器火起来,docker最开始用lxc,觉得隔离性差,开发libcontainer,最终形成runc。所以说,runc是docker的独生子。

K8S时,发现市面上docker挺火,因此就用docker。docker越做越重,CoreOS做了rkt容器格式。rkt与K8S协同工作比较好。容器运行时格式有点多了,linux基金会主导的开源项目说:我们要做一个container runtime标准。叫OCI。以后容器运行时要符合这个标准。docker的独生子runc在第一时间符合了OCI标准。

K8S为了与容器运行时解耦(主要是docker),提出了CRI(Container Runtime Interface)标准。它是一组与K8S与container runtime进行交互的接口。所以说,CRI和OCI并不冲突:K8S定义的是它调用容器运行时的标准接口,OCI定义的是容器运行时本身的标准。

OCI关于容器运行时的标准提出来以后,红帽想可以专门为K8S做一个轻量级的容器运行时。红帽自然会考虑到它自己全力投入的K8S发布的CRI标准(K8S红帽代码贡献第二),因此决定重用了runc等基本组件来启动容器, 并实现了一个最小的 CRI 接口。它叫CRI-O。所以说,CRI-O是CRI的一种标准实现。

当Red Hat正在开发其CRI-O,Docker也在研究CRI标准,这导致创建了另一个名为containerd的运行时(实际上是从docker engine剥离出来的)。所以新版本的docker会多一层containerd。kubernetes将containerd接入到cri的标准中。即cri-containerd。

1.2 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全称是Open Container Initiative,定义得是容器运行时的标准。这个标准,使用Linux的cgroup和namespace等技术,和docker所使用的技术没什么两样。docker只不过是OCI的一个实现而已,就像gVisor(runsc)所实现的一样。

OCI代表Open Container Initiative(开放容器倡议),它标准化了容器工具和技术之间的许多接口。它们维护了包装容器映像(OCI映像规范)和运行容器(OCI运行时规范)的标准规范。它们还以runc的形式维护运行时规范的实际实现,它是containerd和CRI-O的底层默认运行时。CRI构建在这些低层规范之上,为管理容器提供端到端标准。

发展至今, OCI 制定的主要标准有三个分别是 runtime-spec 、image-spec 和 distribution-spec 这三个标准分别定义了容器运行时,容器镜像还有分发的规范。

其实,现阶段,docker只是众多容器技术中的其中一种。它有三个主要的概念:

  • 镜像:代表了最终的软件包,不可变的软件载体。相当于安装文件
  • 容器:镜像的运行时,实际运行的实例,具有明确的进程号
  • 仓库:存放镜像的仓库,可以进行统一的版本管理和权限管理

 

为了支持 OCI 容器运行时标准的推进,Docker 公司起草了镜像格式和运行时规范的草案,并将 Docker 项目的相关实现捐献给了 OCI 作为容器运行时的基础实现,现在项目名为 runc 。后来 Docker 将其容器运行时独立成了一个项目,名为 containerd 并将此项目捐献给了 CNCF ,现在已经是 CNCF 毕业项目了。

Docker公司其实是捐献了Containerd和runC。这俩到底是啥东西。简单的说,runC是OCI标准的实现,也叫OCI运行时,是真正负责操作容器的。Containerd对外提供接口,管理、控制着runC。

docker是运行时和一堆开发工具集合的统称。docker-cli就不必多说了,就是一堆命令行的集合,我们主要看一下运行时:

 

  • docker:我们平常操作docker,使用的就是docker命令,它就是我们所说的命令行接口,相当于一个客户端。它将指令发送到dockerd
  • dockerd:docker的服务端。比如我们在Linux上安装docker,就要启动一个常驻进程,才能管理所有的docker进程.
  • containerd:这个组件,是从11版本才有的,是从dockerd里拆出来的,是容器标准化后的产物,它遵循的是OCI标准。containerd功能齐全,换句话说,你的服务器上可以没有dockerd,只需要containerd就能运行你的容器
  • runc:容器运行时组件,是一个标准的OCI容器实现运行时,可用来直接创建和运行容器。runC是一个轻量级的工具,用来运行容器的,我们可以不用通过docker引擎,直接运行容器。可以看到containerd和runc都是OCI的实现,区别是前者是管理工具,后者是运行容器
  • containerd-shim:垫片的意思,containerd-shim是一个真实运行容器的载体,为了能够支持多种OCI Runtime,containerd内部使用containerd-shim将containerd与真正的容器运行时进行解耦,每启动一个容器都会起一个新的containerd-shim的进程。它通常指定三个因素:容器ID、bundle目录(对应某个容器生成的目录,一般位于:/var/run/docker/containerd/containerID)
  • ctr:也叫做containerd-ctr,是containerd的客户端。此外,containerd 还实现了更丰富的容器接口,可以使用 ctr 工具来调用这些丰富的容器运行时接口,而不只是 CRI 接口。例如:
    • crictl:一个类似 docker 的命令行工具,用来操作 CRI 接口。
    • critest:验证 CRI 接口是否是符合预期。
    • 性能工具:测试接口性能。

 

docker本身而言,包括docker client和dockerd,是一个客户端工具,用来把用户的请求发送给docker daemon(dockerd)。

dockerd:dockerd是对容器相关操作的最上层封装,直接面向操作用户。Docker daemon,一般也会被称为docker engine。dockerd启动时会启动containerd 子进程。

containerd囊括了单机运行一个容器时所需要的一切,为了能够支持多种OCI Runtime,containerd 内部使用containerd-shim,每启动一个容器都会创建一个新的containerd-shim进程,指定容器ID,Bundle目录,运行时的二进制(比如runc)。

docker镜像和containerd镜像通用,但组织方式和存放目录不同,导致docker与ctr命令不通用,各自管理自己的镜像和容器。此外k8s还有客户端命令crictl,用法与docker基本相同,可crictl -h查看用法。

从 Docker 1.11 版本开始,Docker 容器运行就不是简单通过 Docker Daemon 来启动了,而是通过集成 containerd、runc 等多个组件来完成的。虽然 Docker Daemon 守护进程模块在不停的重构,但是基本功能和定位没有太大的变化,一直都是 CS 架构,守护进程负责和 Docker Client 端交互,并管理 Docker 镜像和容器。现在的架构中组件 containerd 就会负责集群节点上容器的生命周期管理,并向上为 Docker Daemon 提供 gRPC 接口。

当我们要创建一个容器的时候,现在 Docker Daemon 并不能直接帮我们创建了,而是请求 containerd 来创建一个容器,containerd 收到请求后,也并不会直接去操作容器,而是创建一个叫做 containerd-shim 的进程,让这个进程去操作容器,我们指定容器进程是需要一个父进程来做状态收集、维持 stdin 等 fd 打开等工作的,假如这个父进程就是 containerd,那如果 containerd 挂掉的话,整个宿主机上所有的容器都得退出了,而引入 containerd-shim 这个垫片就可以来规避这个问题了。

然后创建容器需要做一些 namespaces 和 cgroups 的配置,以及挂载 root 文件系统等操作,这些操作其实已经有了标准的规范,那就是 OCI(开放容器标准),runc 就是它的一个参考实现(Docker 被逼无耐将 libcontainer 捐献出来改名为 runc 的),这个标准其实就是一个文档,主要规定了容器镜像的结构、以及容器需要接收哪些操作指令,比如 create、start、stop、delete 等这些命令。runc 就可以按照这个 OCI 文档来创建一个符合规范的容器,既然是标准肯定就有其他 OCI 实现,比如 Kata、gVisor 这些容器运行时都是符合 OCI 标准的。

所以真正启动容器是通过 containerd-shim 去调用 runc 来启动容器的,runc 启动完容器后本身会直接退出,containerd-shim 则会成为容器进程的父进程, 负责收集容器进程的状态, 上报给 containerd, 并在容器中 pid 为 1 的进程退出后接管容器中的子进程进行清理, 确保不会出现僵尸进程。

而 Docker 将容器操作都迁移到 containerd 中去是因为当前做 Swarm,想要进军 PaaS 市场,做了这个架构切分,让 Docker Daemon 专门去负责上层的封装编排,当然后面的结果我们知道 Swarm 在 Kubernetes 面前是惨败,然后 Docker 公司就把 containerd 项目捐献给了 CNCF 基金会,这个也是现在的 Docker 架构。

文章来自个人专栏
文章 | 订阅
0条评论
作者已关闭评论
作者已关闭评论
0
0