日前专为开发者提供技术分享的又拍云 OpenTalk 公开课邀请了网易有道资深运维开发工程师张晋涛,直播分享《Containerd 上手实际》,具体介绍 Containerd 的倒退历程、次要个性,以及如何将其作为 Kubernetes runtime 的上手实际。以下是直播内容整顿
对于作者:张晋涛,现就职于网易有道,对 Docker、Kubernetes 及相干生态有大量实际及深刻源码的钻研,《Docker 外围常识必知必会》专栏作者。PS 讲师长期保持更新 K8S 生态周报,如有趣味可订阅其公众号【MoeLove】。
大家好,明天分享的内容将会从 Kubernetes 发表弃用 dockershim 说起,介绍 Containerd 相干个性,分享如何将 Containerd 用作 Kubernetes 的 runtime。
Kubernetes 发表弃用 dockershim
很多媒体将该事件声称为 Kubernetes 发表弃用 Docker,其实这是一种误导。那么应该如何正确的去对待呢?首先是理解整个事件的前因后果,得须要晓得 dockershim 是什么。
dockershim
dockershim 是 Kubernetes 的一个组件,次要目标是为了通过 CRI 操作 Docker。Docker 在 2013 年就呈现了,2014 年 Kubernetes 公布并默认应用 Docker 作为容器运行时,而 dockershim 首次正式呈现是在 2016 年。Docker 在创立之初并没有思考到容器编排或者是思考 Kubernetes,但 Kubernetes 在创立之初便采纳 Docker 作为它的默认容器进行时,后续代码当中蕴含了很多对 Docker 相干的操作逻辑。前期 Kubernetes 为了可能做解耦,兼容更多的容器进行时,将操作 Docker 相干逻辑整体独立起来组成了 dockershim。
Container Runtime Interface
再说 CRI(Container Runtime Interface)即容器运行时接口,该概念是由 Kubernetes 提出并在 2016 年底开始利用,其次要指标是加强 Kubernetes 的可扩展性,能够不固定、不捆绑某一个容器运行时,实现可插拔式的容器进行时。比方能够应用 Docker 为容器运行时也能够应用其余的例如 rkt,并且心愿通过凋谢 CRI 这个对立的接口来进步代码的可维护性,而不是须要反对 Docker 时就对 Docker 进行适配,须要反对另一个运行时就得对其做相干的适配。 它心愿是任何一个成为 Kubernetes 的容器运行时都恪守 CRI 对立的接口与标准,实现了 CRI 就能够作为 Kubernetes 的运行时,并不需要关注具体是什么。
为什么要弃用 dockershim
dockershim 的目标是为了 Kubernetes 通过 CRI 操作 Docker,所以 Kubernetes 任何的性能变动或 Docker 有任何的性能个性变更,dockershim 代码必须加以改变保障可能反对变更。另外一个起因是随着容器技术的推动,容器运行时曾经多种多样了,比方本次分享的配角 Containerd,还有 cri-o 以及 rkt 的容器运行时,不过这个 rkt 容器运行时的我的项目曾经不保护了。
此外,原先 Kubernetes 须要去调用 dockershim 跟 Docker 做沟通,Docker 的底层运行时是 containerd,能够发现最终都是要调用 containerd,并且 containerd 本身也是能够反对 CRI 的。那为什么要先绕过一层 Docker 呢?是不是能够间接通过 CRI 跟 Containerd 进行交互呢?这也就造成了当初 Kubernetes 社区心愿弃用 dockershim。
弃用 dockershim 的影响
终端⽤⼾⽆任何影响。这里指的是应用来自云厂商 / 应用他人提供的 Kubernetes 集群的终端用户,他们不须要关注集群自身的容器运行时到底是什么,因为和你交互的都是 Kubernetes 本身的 CRI,而任何一个能够作为 Kubernetes 底层容器运行时的货色都必须是兼容 CRI 接口的,下层就曾经屏蔽掉这个细节了。
对负责保护 Kubernetes 集群的工作人员有肯定影响。当降级 Kubernetes 集群版本时,须要思考是否切换容器进行时。如果目前在用最新版本 Kubernetes V1.20,并且应用 Docker 作为容器运行时,要思考它是否失常工作。其实是能够失常工作的,只是在启动 Kubernetes 的时候会发现一条日志,揭示你以后应用的容器运行时 Docker 曾经不再被 Kubernetes 反对,因为曾经筹备弃用 dockershim,因而会有这个揭示。
Kubernetes 社区打算在 2021 年将 dockershim 正式移除。换个角度思考,既然社区不想在 Kubernetes 源代码当中保护 dockershim 了,那是不是能够把 dockershim 组件给独自的拿进去呢?答案是能够的,当初 Mirantis 和 Docker 曾经决定之后独特单干保护 dockershim 组件。此外,还能够通过树外的 dockershim 独立组件,持续应用 Docker 作为容器运行时,并且应用这种形式只须要做一些简略的配置,把原先应用内置的 Kubernetes 本身携带的 dockershim 组件,改成应用一个独立的 dockershim 组件,自身变动很小。
那么 Docker 到底还是否应用呢?在我看来,毋庸置疑,Docker 依然是现阶段容器构建和运行的最佳抉择。
疾速理解 Containerd
Containerd 是中间层的容器运行时。它构建在平台之下,作为平台上层的一个容器运行时,但又比最底层的容器运行时像 runc、gVisor 要高一点,所以被称为中间层的容器运行时。除此之外也可称作为资源管理器,能够用来治理容器的过程、镜像以及治理文件系统的快照,还有元数据和依赖的治理。既然它能够作为一个资源管理器来应用,如果想要在此之上构建一个属于本人的容器平台就会很不便。
Containerd 是由 Docker 公司创立,并且在 2017 年捐献给了 CNCF,2019 年 Containerd 从 CNCF 正式毕业。Containerd 我的项目一开始的指标是用来治理容器的过程,之后逐渐变更成为一个残缺的容器运行时,是 Docker 的底层容器运行时。须要阐明的是,containerd 是能够抛开 Docker 与 Kubernetes 本身独立工作的。
Containerd 与 CRI
Containerd 在之前的版本中思考到了 CRI,但它是将 CRI 作为独立的过程存在的。在上图中看到,CRI-Containerd 其实是一个独立组件,Kubernetes 通过 CRI 接口调用 CRI-Containerd,再由这个组件去调用 containerd。在 Containerd1.1 版本之后对该个性做了从新的设计,它将 CRI 的反对通过插件化的形式来实现,Kubernetes 通过 CRI 接口调用的其实是 Containerd 当中 CNI 的插件,以此来达到通信的目标,调用链更少更短了。
Containerd 的个性
- 反对 OCI 镜像标准,即前文所提到的 runc
- 反对 OCI 运行时标准。Docker 疏导了 OCI 组织的成立,该组织次要有两个标准:镜像标准与运行时标准。这两个标准在 Docker 成立时把 Docker 镜像标准与底层容器运行时标准都给捐献进去作为它的初始工作
- 反对镜像的 push/pull 作用
- 反对容器网络管理。因为能够启动和运行容器,容器启动后反对相互之间的拜访,或彼此之间网络的隔离,所以须要反对容器网络的治理
- 存储反对多租户。Containerd 的相干操作有通过 namespace 来做隔离的,能够指定不同的 namespace 来实现,它默认的 namespace 叫 default,在 default 的 namespace 上面下载多个镜像。然而在其余的 namespace 下看不到这些镜像,也用不到,以此来达到多租户的隔离
- 反对容器运行时和容器的生命周期治理
- 反对管理网络名称空间容器以退出现有名称空间,能够让某一个容器退出到现有的 namespace 当中
Containerd 的整体架构
上图是 Containerd 整体的架构。由下往上,Containerd 反对的操作系统和架构有 Linux、Windows 以及像 ARM 的一些平台。在这些底层的操作系统之上运行的就是底层容器运行时,其中有上文提到的 runc、gVisor 等。在底层容器运行时之上的是 Containerd 相干的组件,比方 Containerd 的 runtime、core、API、backend、store 还有 metadata 等等。构筑在 Containerd 组件之上以及跟这些组件做交互的都是 Containerd 的 client,Kubernetes 跟 Containerd 通过 CRI 做交互时,自身也作为 Containerd 的一个 client。Containerd 自身有提供了一个 CRI,叫 ctr,不过这个命令行工具并不是很好用。
在这些组件之上就是真正的平台,Google Cloud、Docker、IBM、阿里云、微软云还有 RANCHER 等等都是,这些平台目前都曾经反对 containerd,并且有些曾经作为本人的默认容器运行时了。
Containerd 次要性能与上手实际
镜像治理
首先是上文中频繁提到的镜像治理。具体操作是须要通过一个 client 去跟 Containerd 做交互。如图中所示,这里抉择了 ctr 的命令行工具。ctr 指定一个 address 参数跟 Containerd 交互,它是在后盾继续运行的一个服务,须要指定它的地址。图中是通过 pull 一个 redis alpine linux 的镜像,接下来通过 image ls 就能够看到曾经胜利 pull 下来的镜像。
容器治理
作为一个容器运行时对容器进行治理是必不可少的性能。同样的通过 -a 参数来指定 address 与 Containerd 进行通信,通过 container create+ 镜像名称 + 容器名称来创立一个容器,通过 container ls 能够看到方才创立的容器。须要留神的是,最初一列叫做 runtime,它的 runtime 叫做 io.containerd.runc.v2,表明是 v2 版本的 Containerd API。
在 Containerd 中通过 container create 创立进去的容器其实并不论用,还须要让其运行起来。这时通常会把它当作一个 task,对它执行 task start,就能够把方才创立的镜像跑起来了。通过 task ls 就能够看到名叫 redis 的 Containerd,其中有一个正在运行的过程,并且展现出了过程号。
命名空间
须要阐明的是,能够通过 -n 来指定一个默认的叫做 default 的命名空间,而后通过 task ls 就看到方才启动容器的过程,它其实是在运行中的。如果把 namespace 换一个,比方图中的 moby 就是 Docker 我的项目以后应用的 namespace 名称,Docker 在应用 Containerd 作为容器运行时的时候,会默认应用它。
持续往下看,通过 ctr -n 指定应用 moby 命名空间,-a 参数指定 containerd 的地址,而后 task ls 来看看 moby 我的项目当中到底运行着什么。能够看到有一条记录是正在运行当中的。这条记录如何和 Docker 当中的容器或工作做匹配比拟呢?一个简略的方法就是通过 docker ps –no-trunc– format 跟容器残缺的 ID,而后 grep 就能够看到方才通过 ctr 命令失去的 ID 了。
须要留神的是,如果应用 Containerd 作为 Kubernetes 的容器运行时,那么它的 namespace 叫 k8s.io。到这里可能有些人曾经发现,Containerd 作为 Docker 的运行时能够应用不同的命名空间,比方 moby。用作 Kubernetes 容器运行时也能够应用不同的命名空间,比方 k8s.io。那是否存在一种方法能够让平台当中既有 Kubernetes 又有 Docker,还有 Containerd 呢?答案是必定的,间接将其全副装到一起,但不配置 Docker 作为容器运行时,先察看一段时间看看,这也是一种方法。
Containerd 用作 Kubernetes 的 runtime
上图是 Containerd 用作 Kubernetes 的 runtime 整个流程图。Kubernetes 通过 CRI 接口,调用到 CRI plugin,plugin 是 Containerd 一个内置的插件,其中蕴含了最次要的两局部:一是 image service,蕴含了镜像服务相干的;二是 runtime service,即运行时的服务。如果在 containerd 当中部署了一个我的项目或服务,它首先会调度到某一台机器,这台机器上的 Kubernetes 就会开始工作,它会查问服务、须要哪些镜像,而后把相干的镜像让运行时给拉下来,再去启动对应的 pod 或者相干的容器。
其次它还会跟 CNI 做交互。CNI 即 Container Network Interface,是 Kubernetes 提供的一个容器网络接口)。次要留神的是,交互过程中可能会提前创立进去 pause 的 container,是一个占位的过程,这里先不对此做更深刻的介绍。
当 Containerd 作为 Kubernetes 的容器运行时,配置绝对很简略:通过 containerd config default 命令能够间接查问到 Containerd 残缺的默认配置,下图中能够看到次要是配置 CRI。所以在这里的配置文件当中,通过 plugins.io.containerd.grpc.vi.cri 对其进行配置,首先是 default-runtime,其次配置一个 runtime.runc。
这里简略介绍配置 runc 须要留神的参数。比方 io.containerd.runc.v2 须要配置 runtime.type;波及配置与 runc 相干的一些配置会蕴含一些 CNI 的配置、目录之类的,具体的配置上图中曾经展现了。总而言之如果想要提起来一个服务、一个 pod 或是 container,要留神都是须要配置的。它都会有一个 pause 的镜像,即 sandbox_image,能够从中指定一个默认的镜像。当然也能够通过此处换源,放慢国内环境下的拉取速度。
最初还有些其余的资源,如自己长期参加的一个我的项目 KIND(Kubernetes in docker)。这个我的项目相当于是应用 docker 容器作为不同的 node,能够把这些 node 组成一个集群网络,搭建一套 Kubernetes。而这个集群应用的容器运行时就是 containerd,尽管一开始应用的是 Docker,但前期逐渐都将其替换成了 containerd,相似的还有包含 K3C、K3S,成果都是差不多的。
举荐浏览
云原生网络代理(MOSN)的进化之路
聊聊 HTTP 常见的申请形式