Docker、Containerd、RunC分别是什么
connygpt 2024-12-27 16:04 3 浏览
什么是RunC
上一遍文章《真正运行容器的工具:深入了解 runc 和 OCI 规范》已经讲清楚了Runc与OCI。这里再讲解一下概念。
Docker、Google、CoreOS 和其他供应商创建了开放容器计划 (OCI),目前主要有两个标准文档:容器运行时标准 (runtime spec)和 容器镜像标准(image spec)。
- image.png
OCI 对容器 runtime 的标准主要是指定容器的运行状态,和 runtime 需要提供的命令。下图可以是容器状态转换图:
- init 状态:这个是我自己添加的状态,并不在标准中,表示没有容器存在的初始状态
- creating:使用 create 命令创建容器,这个过程称为创建中
- created:容器创建出来,但是还没有运行,表示镜像和配置没有错误,容器能够运行在当前平台
- running:容器的运行状态,里面的进程处于 up 状态,正在执行用户设定的任务
- stopped:容器运行完成,或者运行出错,或者 stop 命令之后,容器处于暂停状态。这个状态,容器还有很多信息保存在平台中,并没有完全被删除
Runc的来历
RunC 是从 Docker 的 libcontainer 中迁移而来的,实现了容器启停、资源隔离等功能。Docker将RunC捐赠给 OCI 作为OCI 容器运行时标准的参考实现。Docker 默认提供了 docker-runc 实现。事实上,通过 containerd 的封装,可以在 Docker Daemon 启动的时候指定 RunC的实现。最初,人们对 Docker 对 OCI 的贡献感到困惑。他们贡献的是一种“运行”容器的标准方式,仅此而已。它们不包括镜像格式或注册表推/拉格式。当你运行一个 Docker 容器时,这些是 Docker 实际经历的步骤:
- 下载镜像
- 将镜像文件解开为bundle文件,将一个文件系统拆分成多层
- 从bundle文件运行容器
Docker标准化的仅仅是第三步。在此之前,每个人都认为容器运行时支持Docker支持的所有功能。最终,Docker方面澄清:原始OCI规范指出,只有“运行容器”的部分组成了runtime。这种“概念失联”一直持续到今天,并使“容器运行时”成为一个令人困惑的话题。希望我能证明双方都不是完全错误的,并且在本文中将广泛使用该术语。RunC 就可以按照这个 OCI 文档来创建一个符合规范的容器,既然是标准肯定就有其他 OCI 实现,比如 Kata、gVisor 这些容器运行时都是符合 OCI 标准的。
怎么使用 runc
create the bundle
$ mkdir -p /mycontainer/rootfs
# [ab]use Docker to copy a root fs into the bundle
$ docker export $(docker create busybox) | tar -C /mycontainer/rootfs -xvf -
# create the specification, by default sh will be the entrypoint of the container
$ cd /mycontainer
$ runc spec
# launch the container
$ sudo -i
$ cd /mycontainer
$ runc run mycontainerid
# list containers
$ runc list
# stop the container
$ runc kill mycontainerid
# cleanup
$ runc delete mycontainerid
在命令行中使用 runc,我们可以根据需要启动任意数量的容器。但是,如果我们想自动化这个过程,我们需要一个容器管理器。为什么这样?想象一下,我们需要启动数十个容器来跟踪它们的状态。其中一些需要在失败时重新启动,需要在终止时释放资源,必须从注册表中提取图像,需要配置容器间网络等等。就需要有Low-Level和High-Level容器运行时,runc就是Low-Level实现的实现。
Low-Level和High-Level容器运行时
当人们想到容器运行时,可能会想到一系列示例;runc、lxc、lmctfy、Docker(容器)、rkt、cri-o。这些中的每一个都是为不同的情况而构建的,并实现了不同的功能。有些,如 containerd 和 cri-o,实际上使用 runc 来运行容器,在High-Level实现镜像管理和 API。与 runc 的Low-Level实现相比,可以将这些功能(包括镜像传输、镜像管理、镜像解包和 API)视为High-Level功能。考虑到这一点,您可以看到容器运行时空间相当复杂。每个运行时都涵盖了这个Low-Level到High-Level频谱的不同部分。这是一个非常主观的图表:
因此,从实际出发,通常只专注于正在运行的容器的runtime通常称为“Low-Level容器运行时”,支持更多高级功能(如镜像管理和gRPC / Web API)的运行时通常称为“High-Level容器运行时”,“High-Level容器运行时”或通常仅称为“容器运行时”,我将它们称为“High-Level容器运行时”。值得注意的是,Low-Level容器运行时和High-Level容器运行时是解决不同问题的、从根本上不同的事物。
- Low-Level容器运行时:容器是通过Linux nanespace和Cgroups实现的,Namespace能让你为每个容器提供虚拟化系统资源,像是文件系统和网络,Cgroups提供了限制每个容器所能使用的资源的如内存和CPU使用量的方法。在最低级别的运行时中,容器运行时负责为容器建立namespaces和cgroups,然后在其中运行命令,Low-Level容器运行时支持在容器中使用这些操作系统特性。目前来看低级容器运行时有:runc :我们最熟悉也是被广泛使用的容器运行时,代表实现Docker。runv:runV 是一个基于虚拟机管理程序(OCI)的运行时。它通过虚拟化 guest kernel,将容器和主机隔离开来,使得其边界更加清晰,这种方式很容易就能帮助加强主机和容器的安全性。代表实现是kata和Firecracker。runsc:runsc = runc + safety ,典型实现就是谷歌的gvisor,通过拦截应用程序的所有系统调用,提供安全隔离的轻量级容器运行时沙箱。截止目前,貌似并不没有生产环境使用案例。wasm : Wasm的沙箱机制带来的隔离性和安全性,都比Docker做的更好。但是wasm 容器处于草案阶段,距离生产环境尚有很长的一段路。
- High-Level容器运行时:通常情况下,开发人员想要运行一个容器不仅仅需要Low-Level容器运行时提供的这些特性,同时也需要与镜像格式、镜像管理和共享镜像相关的API接口和特性,而这些特性一般由High-Level容器运行时提供。就日常使用来说,Low-Level容器运行时提供的这些特性可能满足不了日常所需,因为这个缘故,唯一会使用Low-Level容器运行时的人是那些实现High-Level容器运行时以及容器工具的开发人员。那些实现Low-Level容器运行时的开发者会说High-Level容器运行时比如containerd和cri-o不像真正的容器运行时,因为从他们的角度来看,他们将容器运行的实现外包给了runc。但是从用户的角度来看,它们只是提供容器功能的单个组件,可以被另一个的实现替换,因此从这个角度将其称为runtime仍然是有意义的。即使containerd和cri-o都使用runc,但是它们是截然不同的项目,支持的特性也是非常不同的。dockershim, containerd 和cri-o都是遵循CRI的容器运行时,我们称他们为高层级运行时(High-level Runtime)。
Kubernetes 只需支持 containerd 等high-level container runtime即可。由containerd 按照OCI 规范去对接不同的low-level container runtime,比如通用的runc,安全增强的gvisor,隔离性更好的runv。
containerd
与RunC_一样_,我们又可以在这里看到一个docker公司的开源产品containerd曾经是开源docker项目的一部分。尽管_containerd_是另一个自给自足的软件。
- 一方面,它称自己为容器运行时,但是与运行时__RunC_不同_。不仅_containerd_和_runc_的职责不同,组织形式也不同。显然_runc_是只是一个命令行工具,_containerd_是一个长期居住守护进程。_runc_的实例不能超过底层容器进程。通常它在create调用时开始它的生命,然后只是在容器的 rootfs 中的指定文件去运行。
- 另一方面,_containerd _可以管理超过数千个_runc_容器。它更像是一个服务器,它侦听传入请求以启动、停止或报告容器的状态。在引擎盖下_containerd_使用RunC。然而,_containerd_不仅仅是一个容器生命周期管理器。它还负责镜像管理(从注册中心拉取和推送镜像,在本地存储镜像等)、跨容器网络管理和其他一些功能。
image.png
containerd 是一个工业级标准的容器运行时,它强调简单性、健壮性和可移植性,containerd 可以负责干下面这些事情:
- 管理容器的生命周期(从创建容器到销毁容器)
- 拉取/推送容器镜像
- 存储管理(管理镜像及容器数据的存储)
- 调用 runc 运行容器(与 runc 等容器运行时交互)
- 管理容器网络接口及网络
上图是 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, 并且有些已经作为自己的默认容器运行时了。
从 k8s 的角度看,选择 containerd作为运行时的组件,它调用链更短,组件更少,更稳定,占用节点资源更少。
Docker
Docker 于 2013 年发布,解决了开发人员在端到端运行容器时遇到的许多问题。这里是他包含的所有东西:
- 容器镜像格式
- 一种构建容器镜像的方法(Dockerfile/docker build);
- 一种管理容器镜像(docker image、docker rm等);
- 一种管理容器实例的方法(docker ps, docker rm 等);
- 一种共享容器镜像的方法(docker push/pull);
- 一种运行容器的方式(docker run);
当时,Docker 是一个单体系统。但是,这些功能中没有一个是真正相互依赖的。这些中的每一个都可以在可以一起使用的更小、更集中的工具中实现。每个工具都可以通过使用一种通用格式、一种容器标准来协同工作。从 Docker 1.11 之后,Docker Daemon 被分成了多个模块以适应 OCI 标准。拆分之后,结构分成了以下几个部分。
其中,containerd 独立负责容器运行时和生命周期(如创建、启动、停止、中止、信号处理、删除等),其他一些如镜像构建、卷管理、日志等由 Docker Daemon 的其他模块处理。
Docker 的模块块拥抱了开放标准,希望通过 OCI 的标准化,容器技术能够有很快的发展。
现在创建一个docker容器的时候,Docker Daemon 并不能直接帮我们创建了,而是请求 containerd 来创建一个容器。当containerd 收到请求后,也不会直接去操作容器,而是创建一个叫做 containerd-shim 的进程。让这个进程去操作容器,我们指定容器进程是需要一个父进程来做状态收集、维持 stdin 等 fd 打开等工作的,假如这个父进程就是 containerd,那如果 containerd 挂掉的话,整个宿主机上所有的容器都得退出了,而引入 containerd-shim 这个垫片就可以来规避这个问题了,就是提供的live-restore的功能。这里需要注意systemd的 MountFlags=slave。
然后创建容器需要做一些 namespaces 和 cgroups 的配置,以及挂载 root 文件系统等操作。runc 就可以按照这个 OCI 文档来创建一个符合规范的容器。
真正启动容器是通过 containerd-shim 去调用 runc 来启动容器的,runc 启动完容器后本身会直接退出,containerd-shim 则会成为容器进程的父进程, 负责收集容器进程的状态, 上报给 containerd, 并在容器中 pid 为 1 的进程退出后接管容器中的子进程进行清理, 确保不会出现僵尸进程。containerd,containerd-shim和容器进程(即容器主进程)三个进程,是有依赖关系的。可以参考《containerd,containerd-shim和runc的依存关系》[1],查看怎么保证live-restore的功能的。
相关推荐
- vue3 组件初始化流程
-
学习完成响应式系统后,咋们来看看vue3组件的初始化流程既然是看vue组件的初始化流程,咋们先来创建基本的代码,跑跑流程(在app.vue中写入以下内容,来跑流程)import{h,ref}...
- Context的典型使用场景
-
获取应用文件路径基类Context提供了获取应用文件路径的能力,ApplicationContext、AbilityStageContext、UIAbilityContext和ExtensionCon...
- web技术分享|AudioContext 实现音频可视化
-
要实现音频可视化,实现一些炫酷的效果需要借助WebAudioAPI提供的一些方法AudioContext。AudioContext接口表示由链接在一起的音频模块构建的音频处理图,每个模块由一个...
- 2023-03-21:音视频解混合(demuxer)为MP3和H264,用go语言编写
-
2023-03-21:音视频解混合(demuxer)为MP3和H264,用go语言编写。答案2023-03-21:#步骤1:安装github.com/moonfdd/ffmpeg-gogoget...
- 如何在微信小程序中加入音频或视频?
-
要在微信小程序中加入音频或视频,可以使用以下步骤:1.在小程序页面中引入wx.createInnerAudioContext()或wx.createVideoContext()方法。2.创建音频或...
- 使用RKE的方式快速部署K8S集群
-
RKE是一款经过CNCF认证的开源Kubernetes发行版,可以在Docker容器内运行。它通过删除大部分主机依赖项,并为部署、升级和回滚、节点扩容提供一个稳定的路径,从而解决了Kubernetes...
- Rancher(k8s)的持久存储卷Volumes(PV/PVC)的使用方法
-
1.介绍1.1介绍在上一节课里面福哥带着大家学会了使用k8s的负载均衡LoadBalancing(LB)发布集群内部的服务的方法,今天我们要讲讲k8s的持久存储卷Volumes(PVC)的使用方...
- 基于 Sealos 的镜像构建能力,快速部署自定义 k8s 集群
-
Sealos是一个快速构建高可用k8s集群的命令行工具,该工具部署时会在第一个k8smaster节点部署registry服务(sealos.hub),该域名通过hosts解析到第一...
- Docker、Containerd、RunC分别是什么
-
什么是RunC上一遍文章《真正运行容器的工具:深入了解runc和OCI规范》已经讲清楚了Runc与OCI。这里再讲解一下概念。Docker、Google、CoreOS和其他供应商创建了开放容...
- 偷偷爆料下Docker学习,看这一篇就够了!十分推荐!!
-
一.什么是容器?生活中常将一个能用来承载物料的装置称之为容器,比如碗、盘子,杯子等,容器内可放入各种各样的物料,每一个容器都相互独立,不相互干扰。而我们计算机领域所说的容器通常是指一个包含了完整的运...
- Docker网络优化方案,你认为哪种将引爆未来?
-
ICT架构师技术交流微信号分析和交流ICT行业最前沿技术,分享更多存储、服务器、数据中心、网络、软件定义和虚拟化等相关知识,旨在知识交流、开放共享和共同进步。上一篇文章Docker原生网络和实现原...
- Docker容器和存储系统 云舒网络
-
江松:1986开始接触到苹果电脑,不是MacBook,是APPLEII.用Basic编程序。1999年去欧洲爱尔兰做存储,从并行SCSI协议开始做,到FC1G,4G,8G。2009年回国后进...
- 基于docker的跨主机WEB容器管理
-
前言由于我们的一部分服务器,分布在不同的公共网络环境。而且,这些服务器程序,发布都使用了docker,但并没有使用k8s这样的工具。处于离散的管理状态。也考虑过rancher这样的工具,但对于我们来说...
- Kubernetes(k8s)docker 和 Containerd 区别
-
Kubernetes(k8s)、Docker和Containerd都是容器技术领域的重要工具,但它们各自有不同的角色和功能。Docker:Docker是一个开源的容器化平台,它允许开发者将应...
- 从 Docker 快刀到 K8s 剑法:程序员的云原生武功秘籍
-
前言在当今云计算的浪潮中,Docker和Kubernetes(K8s)已成为每位程序员必备的核心工具。Docker,如同一把锐利的快刀,能够迅速、简洁地将应用及其依赖封装成镜像,实现便捷的打包与发...
- 一周热门
- 最近发表
- 标签列表
-
- kubectlsetimage (56)
- mysqlinsertoverwrite (53)
- addcolumn (54)
- helmpackage (54)
- varchar最长多少 (61)
- 类型断言 (53)
- protoc安装 (56)
- jdk20安装教程 (60)
- rpm2cpio (52)
- 控制台打印 (63)
- 401unauthorized (51)
- vuexstore (68)
- druiddatasource (60)
- 企业微信开发文档 (51)
- rendertexture (51)
- speedphp (52)
- gitcommit-am (68)
- bashecho (64)
- str_to_date函数 (58)
- yum下载包及依赖到本地 (72)
- jstree中文api文档 (59)
- mvnw文件 (58)
- rancher安装 (63)
- nginx开机自启 (53)
- .netcore教程 (53)