从Docker和Kubernetes看Containerd

这篇具有很好参考价值的文章主要介绍了从Docker和Kubernetes看Containerd。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

导读:

在学习Containerd之前,我们需要去了解Docker与Kubernetes这两个使用Containerd最多的技术,也需要明白什么是容器,什么是容器运行时,以及里面涉及的组件,这些组件是用来干什么的,及容器领域的概念,如libcontainer、runc、OCI、CRI、shim等。

什么是容器?

在 Linux 内核中,容器不是一类对象。容器本质上由几个底层的内核原语组成:namespace(允许你跟谁交谈),cgroup(允许使用的资源量),和 LSM(Linux 安全模块 —— 允许你做的事情)。这些凑在一起能够为我们的进程设置安全、隔离和可计量的执行环境。

每次创建隔离进程时,都不需要手动隔离、自定义命名空间等,把这些组件捆绑在一起,我们称之为容器。但是每次手动执行所有的操作将很麻烦,因此出现了容器运行时工具,它能将这些部分组合成一个隔离的、安全的执行环境变得很容易,让我们能以重复的方式部署。

什么是容器运行时?

容器运行时是掌控容器运行的整个生命周期,以docker为例,其主要提供功能如下:

  • 制定容器镜像格式

  • 构建容器镜像

  • 管理容器镜像

  • 管理容器实例

  • 运行容器

  • 实现容器镜像共享

这些功能均可由小的组件单独实现,因此容器运行时是运行和管理容器运行所需要的组件。

随着容器运行时的发展,Docker公司与CoreOS和Google共同创建了OCI(开放容器标准),并提供了两种规范:

  • 运行时规范:该规范目标是定义容器的配置、执行环境和生命周期

  • 镜像规范:该规范的目标创建可互操作的工具,用于构建、传输和准备要运行的容器镜像

在runc作为了OCI的一种实现参考之后,各种运行时工具和库也慢慢出现。而根据这些运行时的功能不同,比如有的只运行容器(runc,lxc),有的还可以对镜像进行管理(Containerd,cri-o),因此通俗的分为高级运行时(high-level)和低级运行时(low-level)。

低级运行时:侧重于运行容器,为容器设置namespace和cgroup

  • lxc

  • rkt

  • runc

  • kata

  • gVisor

高级运行时:包含更多上层功能,如为开发人员提供API,镜像存储管理等

  • Containerd

  • cri-o

  • docker

Docker

Docker是第一个流行的容器技术,最初Docker使用的是LXC(0.7版本之前)但是隔离的层次不完善,后来Docker开发了libcontainer(0.7~1.10版本),最后演变为runc和Containerd(Docker被逼无奈将libcontainer捐献出来改名为runc)。

从1.11版本之后,Docker容器运行开始通过集成Containerd和runc等多个组件完成。现在的架构中,Containerd负责容器的生命周期管理,提供了在一个节点上执行容器和管理镜像的最小功能集,并向上为Docker Daemon提供grpc接口。

从Docker和Kubernetes看Containerd

当请求创建一个容器时,Docker Daemon并不会直接去创建,而且请求containerd创建容器,containerd在收到请求后,也不会去直接操作容器,而是创建containerd-shim的进程去操作容器(因为需要一个父进程去做状态收集、维持stdin、stdout、stderr打开等工作,如果父进程是contaienrd,当containerd挂掉时,整个宿主机的容器都会退出),而containerd-shim会去调用runc来启动容器,runc在启动完容器后会直接退出,此时containerd-shim成为容器的父进程,负责收集容器进程的状态上报给containerd,并在容器中 pid 为 1 的进程退出后接管容器中的子进程进行清,确保不会出现僵尸进程。

runc创建容器则是根据上述的OCI去做操作,例如namespaces、cgroups的配置,以及挂载root文件系统等操作。

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

Kubernetes

2014年Kubernetes诞生,由于当时Docker很流行,因此很自然的选择了Docker,在CRI出现之前,Kubelet通过内嵌的dockershim操作Docker API来操作容器,进而达到一个面向终态的效果。

从Docker和Kubernetes看Containerd

而随着Docker将Containerd开源出以及更多的容器运行时出来,Kubernetes为了精简和支持更多的容器运行时,Google和Redhat推出了CRI标准,用于Kubernetes平台和容器运行时解耦CRI(容器运行时接口)。

CRI本质上是Kubernetes定义的一组与容器运行时进行交互的接口,因此容器运行时只要实现了CRI,就可以对接到Kubernetes平台中。但是当时Kubernetes的地位不高,所以一些容器运行时不会去实现CRI接口,于是就出现了shim,shim的职责是作为适配器将各种容器运行时本身的接口适配到 Kubernetes 的 CRI 接口上,上图的dockershim就是Kubernetes对接Docker到CRI接口的实现。

从Docker和Kubernetes看Containerd

在引入CRI后,Kubelet的架构如图所示:

从Docker和Kubernetes看Containerd

通过观察分析能够发现,Kubernetes使用Docker的调用链比较长,而Docker的一些功能对于Kubernetes来说又不需要,所以自然的将容器运行时切换到Containerd。切换到Containerd后取消掉了中间环节,但操作体验和以前一样,在Containerd1.0时,对CRI的适配是通过一个单独的CRI-Containerd实现(因为最开始containerd还会去适配其他系统,所以没有直接实现CRI)。到了Containerd1.1版本后就去掉了CRI-Containerd,直接把适配逻辑作为插件集成到Containerd主进程中,变得更加简洁。

从Docker和Kubernetes看Containerd

CRI的接口主要分为两类:

  • ImageService:镜像相关的操作

  • RuntimeService:容器和Sandbox运行时管理

RuntimeService 中 CRI 设计的一个重要原则,就是确保这个接口本身,只关注容器,不关注 Pod,这么做是因为:

  • Pod 是 Kubernetes 的编排概念,而不是容器运行时的概念。所以,我们就不能假设所有下层容器项目,都能够暴露出可以直接映射为 Pod 的 API;

  • 如果 CRI 里引入了关于 Pod 的概念,那么接下来只要 Pod API 对象的字段发生变化,那么 CRI 就很有可能需要变更。而在 Kubernetes 开发的前期,Pod 对象的变化还是比较频繁的,但对于 CRI 这样的标准接口来说,这个变更频率就有点麻烦了。

从Docker和Kubernetes看Containerd

虽然 CRI 里还是有一组叫做 RunPodSandbox 的接口。但是,这个 PodSandbox,对应的并不是 Kubernetes 里的 Pod API 对象,而只是抽取了 Pod 里的一部分与容器运行时相关的字段,比如 HostName、DnsConfig、CgroupParent 等。所以说,PodSandbox 这个接口描述的其实是 Kubernetes 将 Pod 这个概念映射到容器运行时层面所需要的字段,或者说是一个 Pod 对象的子集。而创建、管理 Pod 的逻辑则放置在 kubernetes 中,而不是 CRI 要实现的接口中。

随着 CRI 方案的发展,以及其他容器运行时对 CRI 的支持越来越完善,Kubernetes 社区在2020年7月份就开始着手移除 dockershim 方案了,现在的移除计划是在 1.20 版本中将 kubelet 中内置的 dockershim 代码分离,将内置的 dockershim 标记为维护模式,当然这个时候仍然还可以使用 dockershim,目标是在 1.24 版本发布没有 dockershim 的版本(代码还在,但是要默认支持开箱即用的 docker 需要自己构建 kubelet,会在某个宽限期过后从 kubelet 中删除内置的 dockershim 代码)。

CRI的实现

目前,CRI领域有两个主要的参与者,一个是Docker的高级运行时Containerd,一个是RedHat专门为Kubernetes设计的运行时CRI-O。

CRI-O

当容器运行时的标准被提出以后,RedHat的一些人开始想他们可以构建一个更简单的运行时,而且这个运行时仅仅为Kubernetes所用。这样就有了skunkworks项目,最后定名为 CRI-O, 它实现了一个最小的CRI接口,旨在充当CRI和支持的OCI运行时的轻量级桥梁。

从Docker和Kubernetes看Containerd

CONTAINERD

Containerd 是一个工业级标准的容器运行时,它强调简单性、健壮性和可移植性,可以在宿主机中管理完整的容器生命周期:容器镜像的传输和存储、容器的执行和管理、存储和网络等,主要有以下功能:

  • 管理容器的生命周期(从创建容器到销毁容器)

  • 拉取/推送容器镜像

  • 存储管理(管理镜像及容器数据的存储)

  • 调用 runc 运行容器(与 runc 等容器运行时交互)

  • 管理容器网络接口及网络(CNI)

Containerd在Docker或者Kunernetes中都是使用最多的运行时,同时也是我们环境中接触最多的,因此后续着重学习Containerd。

Containerd

Containerd 可用作 Linux 和 Windows 的守护程序,它管理其主机系统完整的容器生命周期,从镜像传输和存储到容器执行和监测,再到底层存储到网络附件等等。

从Docker和Kubernetes看Containerd

为了解耦,Containerd 将系统划分成了不同的组件,每个组件都由一个或多个模块协作完成(Core 部分),每一种类型的模块都以插件的形式集成到 Containerd 中,而且插件之间是相互依赖的,例如,上图中的每一个长虚线的方框都表示一种类型的插件,包括 Service Plugin、Metadata Plugin、GC Plugin、Runtime Plugin 等,其中 Service Plugin 又会依赖 Metadata Plugin、GC Plugin 和 Runtime Plugin。每一个小方框都表示一个细分的插件,例如 Metadata Plugin 依赖 Containers Plugin、Content Plugin 等。比如:

  • Content Plugin: 提供对镜像中可寻址内容的访问,所有不可变的内容都被存储在这里

  • Snapshot Plugin: 用来管理容器镜像的文件系统快照,镜像中的每一层都会被解压成文件系统快照,类似于 Docker 中的 graphdriver

总体来看 Containerd 可以分为三个大块:

  • Storage 管理镜像文件的存储

  • Metadata 管理镜像和容器的元数据

  • Runtime 由Task触发的运行时

从Docker和Kubernetes看Containerd

Containerd被设计成可以很容易的嵌入到更大的系统中,例如Docker使用containerd运行容器,Kubernetes通过CRI使用containerd管理单个 节点上的容器 除了编程方式使用外,它还可以通过命令行使用,但不像docker全面,主要用于调试和学习目的,主要有:

  • ctr Containerd依据自身开发的命令行工具

  • nerdctl 与docker命令行风格兼容的命令行工具

  • crictl K8S根据CRI规范定义的命令行工具

从Docker和Kubernetes看Containerd

GRPC API

Containerd通过暴露的gRPC API给外部管理容器,而Containerd中主要提供的API有:

其他还包括events、diffs等,具体见containerd的gRPC API

从Docker和Kubernetes看Containerd

创建容器流程

Docker、ctr、nerdctl都是通过Containerd提供的API进行容器的管理,Kubernetes、crictl则是通过CRI接口实现。

使用gRPC API创建容器

  • 分配一个新的读写快照(snapshot),使得容器可以存储持久化数据(为容器创建新快照时,需要提供快照ID以及容器使用的镜像)

  • 创建一个Container对象,用于分配数据

  • 创建一个Task,用于实际的运行容器(当Task已创建时,意味着命名空间、根文件系统和各种容器级别的设置已被初始化,但容器定义的进程尚未启动)

  • 在启动Task之前需要等待Task创建成功,然后再调用Start去启动Task

从Docker和Kubernetes看Containerd

Kubelet创建Pod流程

  • 调用CRI插件,通过RuntimeService创建Pod

  • CRI调用CNI接口创建和配置Pod的网络命令空间

  • CRI调用Containerd内部接口创建特殊的pause容器,并将该容器放入Pod的cgroups和namespace中(使用不同的容器运行时,PodSandbox的实现方式也不一样,比如使用kata作为runtime,PodSandbox被实现为一个虚拟机;而使用runc作为runtime,PodSandbox就是一个独立的namespace和cgroups)

  • 调用CRI插件,通过ImageServie拉取应用容器镜像

  • 如果节点上不存在镜像,则使用Contianerd拉取镜像

  • 调用CRI插件,使用RuntimeService创建和启动应用容器

  • CRI调用Containerd内部接口创建容器,放到Pod的cgroups和namespace中

从Docker和Kubernetes看Containerd

Containerd创建任务流程

上述说的创建容器流程和创建Pod流程都是调用Containerd内部接口的逻辑,实际的过程由Containerd启动Containerd-shim进程调用runc创建容器,具体步骤如下:

  • Containerd调用Containerd-shim start 启动用于创建runc的Containerd-shim,这样Containerd-shim就与Containerd脱离了关系,重启Containerd也不会影响Containerd-shim进程

  • 通过ttrpc调用Containerd-shim的Newtask方法,之后调用runc create

  • 再通过ttrpc调用Containerd-shim的Start方法,之后调用runc start启动pause容器

  • 以同样的方式启动Pod中定义的container

从Docker和Kubernetes看Containerd

1.   Containerd 被设计成嵌入到一个更大的系统中,而不是直接由开发人员或终端用户使用

2.   Docker有网络功能模块,比如它会创建 docker0 网桥,所以在使用 docker 时可以直接实现端口映射等功能,而这些网络能力都是 Docker Daemon 实现的。但是Containerd 中不包含相应的网络功能,想要启动的容器有网络能力,需要额外安装 CNI 相关的工具和插件(bridge、flannel 等)

*Containerd一切皆插件

总结

本文通过引入Docker和Kubernetes的发展介绍容器、容器运行时,将容器领域c常见的概念OCI、CRI、shim、runc,containerd串联起来,能够帮组我们进一步理解Docker和Kubernetes背后是怎么创建容器的,以及Containerd的实际运行原理。

参考

  • https://github.com/containerd/containerd

  • https://github.com/kubernetes

  • https://github.com/moby/moby

  • https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/2221-remove-dockershim

  • 一文搞懂容器运行时

  • containerd shim原理深入解读文章来源地址https://www.toymoban.com/news/detail-483156.html

到了这里,关于从Docker和Kubernetes看Containerd的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Containerd+Kubernetes搭建k8s集群

    视频教程地址:https://space.bilibili.com/3461573834180825/channel/seriesdetail?sid=3316691 之前写了一篇基于docker安装kubernetes的文章,这篇文档我们来使用containerd来安装kubernetes,相较于docker,containerd运行容器的时候效率更高,并且可以兼容docker镜像。基于docker安装kubernetes的文章地址:ht

    2024年02月07日
    浏览(43)
  • Kubernetes高可用集群二进制部署(Runtime Containerd)

    Kubernetes(简称为:k8s)是Google在2014年6月开源的一个容器集群管理系统,使用Go语言开发,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单并且高效,Kubernetes提供了资源调度、部署管理、服务发现、扩容缩容、监控,维护等一整套功能

    2024年02月08日
    浏览(88)
  • Kubernetes ≥ 1.25 Containerd配置Harbor私有镜像仓库

    containerd 实现了 kubernetes 的 Container Runtime Interface (CRI) 接口,提供容器运行时核心功能,如镜像管理、容器管理等,相比 dockerd 更加简单、健壮和可移植。 从docker过度还是需要一点时间慢慢习惯的,今天来探讨containerd 如何从无域名与权威证书的私有仓库harbor,下载镜像! c

    2024年01月15日
    浏览(44)
  • Centos 7 上基于 containerd 安装 Kubernetes 1.27 集群

    应用 sysctl 参数,无需重启, 完结!

    2024年02月05日
    浏览(34)
  • 使用containerd从0搭建k8s(kubernetes)集群

    准备两台服务器节点,如果需要安装虚拟机,可以参考《wmware和centos安装过程》 机器名 IP 角色 CPU 内存 centos01 192.168.109.130 master 4核 2G centos02 192.168.109.131 node 4核 2G 设置主机名,所有节点都执行 关闭防火墙,所有节点都执行 关闭swap内存,所有节点都执行 配置网桥,所有节点

    2024年02月08日
    浏览(64)
  • jenkins发布Kubernetes(K8s)集群(基于containerd)

    上一篇文章 Jenkins入门与安装 1、k8s环境 版本 v1.26.5 ,容器为containerd 二进制安装Kubernetes(K8s)集群(基于containerd)—从零安装教程(带证书) 主机名 IP 系统版本 安装服务 master01 10.10.10.21 rhel7.5 nginx、etcd、api-server、scheduler、controller-manager、kubelet、proxy master02 10.10.10.22 rhel7.5 ngin

    2024年02月09日
    浏览(91)
  • Kubernetes 1.25.0 基于containerd的部署(rockylinux8.6)

    1、环境说明(安装时配置IP及主机名) 序号 主机IP 主机名 系统 备注 1 192.168.3.114 master rockylinux8.6最小化安装 控制节点 2 192.168.3.115 node1 rockylinux8.6最小化安装 工作节点 3 192.168.3.116 node2 rockylinux8.6最小化安装 工作节点 2、关闭selinux,firewalld及swap分区(在三台设备上执行) 注:sw

    2024年02月02日
    浏览(42)
  • [kubernetes]二进制部署k8s集群-基于containerd

    k8s从1.24版本开始不再直接支持docker,但可以自行调整相关配置,实现1.24版本后的k8s还能调用docker。其实docker自身也是调用containerd,与其k8s通过docker再调用containerd,不如k8s直接调用containerd,以减少性能损耗。 除了containerd,比较流行的容器运行时还有podman,但是podman官方安装

    2024年02月12日
    浏览(53)
  • 《Kubernetes部署篇:Ubuntu20.04基于containerd部署kubernetes1.24.12单master集群》

    如下图所示: 主机名 K8S版本 系统版本 内核版本 IP地址 备注 k8s-master-62 1.24.12 Ubuntu 20.04.5 LTS 5.15.0-69-generic 192.168.1.62 master节点 k8s-worker-63 1.24.12 Ubuntu 20.04.5 LTS 5.15.0-69-generic 192.168.1.63 worker节点 k8s-worker-64 1.24.12 Ubuntu 20.04.5 LTS 5.15.0-69-generic 192.168.1.64 worker节点 说明:分别在对应的

    2023年04月25日
    浏览(46)
  • Prometheus+Grafana(外)监控Kubernetes(K8s)集群(基于containerd)

    1、k8s环境 版本 v1.26.5 二进制安装Kubernetes(K8s)集群(基于containerd)—从零安装教程(带证书) 主机名 IP 系统版本 安装服务 master01 10.10.10.21 rhel7.5 nginx、etcd、api-server、scheduler、controller-manager、kubelet、proxy master02 10.10.10.22 rhel7.5 nginx、etcd、api-server、scheduler、controller-manager、kubel

    2024年02月16日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包