首页 > 其他分享 >容器运行时

容器运行时

时间:2023-10-17 23:33:00浏览次数:32  
标签:容器 containerd runc Docker CRI 运行

容器运行时是一个负责运行和管理容器的软件。它负责创建、启动、停止和监控容器。它也负责为容器提供和宿主机器隔离的运行环境,包括文件系统、网络堆栈、进程空间等。

有多种类型的容器运行时,包括:

  1. Docker:这可能是最为人所知的容器运行时。Docker 通过简化容器的创建和管理,使得容器技术变得更加易用。
  2. containerd:这是一个开源的容器运行时,是 Docker 的一个组件,但也可以独立于 Docker 运行。containerd 用于管理容器的完整生命周期,包括镜像传输和存储、容器执行和监控、低级存储和网络接口。
  3. runc:这是一个符合 Open Container Initiative(OCI)规范的轻量级容器运行时。Docker 和 containerd 使用 runc 来运行容器。
  4. CRI-O:这是一个实现了 Kubernetes Container Runtime Interface(CRI)的轻量级容器运行时。CRI-O 专门针对 Kubernetes 设计,使得 Kubernetes 可以直接运行 OCI 兼容的容器。

runc 是一个命令行工具,用于根据 OCI(Open Container Initiative)规范创建和运行容器。OCI 是一个开放的容器标准,定义了容器的运行时规范(runtime specification)和映像规范(image specification)。Docker 以及其他一些容器平台实际上使用的都是 runc 或其他兼容 OCI 规范的工具来创建和运行容器。

runc 的主要职责包括:

  • 创建、启动和监控容器的进程
  • 对容器进程进行资源隔离(如 CPU、内存、I/O 等)
  • 管理容器的生命周期

在 Docker 中,当你运行一个容器时(例如使用 docker run 命令),Docker 会调用 runc(或 Docker 的默认运行时)来实际创建和启动容器。runc 是一个底层的工具,对于大多数 Docker 用户来说,通常不需要直接与 runc 交互。

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

容器运行时_Docker

当我们要创建一个容器的时候,现在 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 的进程退出后接管容器中的子进程进行清理,确保不会出现僵尸进程。

CRI(Container Runtime Interface 容器运行时接口)本质上就是 Kubernetes 定义的一组与容器运行时进行交互的接口,所以只要实现了这套接口的容器运行时都可以对接到 Kubernetes 平台上来。不过 Kubernetes 推出 CRI 这套标准的时候还没有现在的统治地位,所以有一些容器运行时可能不会自身就去实现 CRI 接口,于是就有了 shim(垫片), 一个 shim 的职责就是作为适配器将各种容器运行时本身的接口适配到 Kubernetes 的 CRI 接口上,其中 dockershim 就是 Kubernetes 对接 Docker 到 CRI 接口上的一个垫片实现。

容器运行时_Docker_02

Kubelet 通过 gRPC 框架与容器运行时或 shim 进行通信,其中 kubelet 作为客户端,CRI shim(也可能是容器运行时本身)作为服务器。

容器运行时_docker_03

容器运行时_Docker_04

现在如果我们使用的是 Docker 的话,当我们在 Kubernetes 中创建一个 Pod 的时候,首先就是 kubelet 通过 CRI 接口调用 dockershim,请求创建一个容器,kubelet 可以视作一个简单的 CRI Client, 而 dockershim 就是接收请求的 Server,不过他们都是在 kubelet 内置的。

dockershim 收到请求后,转化成 Docker Daemon 能识别的请求,发到 Docker Daemon 上请求创建一个容器,请求到了 Docker Daemon 后续就是 Docker 创建容器的流程了,去调用 containerd,然后创建 containerd-shim 进程,通过该进程去调用 runc 去真正创建容器。

其实我们仔细观察也不难发现使用 Docker 的话其实是调用链比较长的,真正容器相关的操作其实 containerd 就完全足够了,Docker 太过于复杂笨重了,当然 Docker 深受欢迎的很大一个原因就是提供了很多对用户操作比较友好的功能,但是对于 Kubernetes 来说压根不需要这些功能,因为都是通过接口去操作容器的,所以自然也就可以将容器运行时切换到 containerd 来。

容器运行时_Docker_05

切换到 containerd 可以消除掉中间环节,操作体验也和以前一样,但是由于直接用容器运行时调度容器,所以它们对 Docker 来说是不可见的。 因此,你以前用来检查这些容器的 Docker 工具就不能使用了。

你不能再使用 docker ps 或 docker inspect 命令来获取容器信息。由于不能列出容器,因此也不能获取日志、停止容器,甚至不能通过 docker exec 在容器中执行命令。

当然我们仍然可以下载镜像,或者用 docker build 命令构建镜像,但用 Docker 构建、下载的镜像,对于容器运行时和 Kubernetes,均不可见。为了在 Kubernetes 中使用,需要把镜像推送到镜像仓库中去。

从上图可以看出在 containerd 1.0 中,对 CRI 的适配是通过一个单独的 CRI-Containerd 进程来完成的,这是因为最开始 containerd 还会去适配其他的系统(比如 swarm),所以没有直接实现 CRI,所以这个对接工作就交给 CRI-Containerd 这个 shim 了。

然后到了 containerd 1.1 版本后就去掉了 CRI-Containerd 这个 shim,直接把适配逻辑作为插件的方式集成到了 containerd 主进程中,现在这样的调用就更加简洁了。

容器运行时_docker_06

与此同时 Kubernetes 社区也做了一个专门用于 Kubernetes 的 CRI 运行时 CRI-O,直接兼容 CRI 和 OCI 规范。

容器运行时_docker_07

Containerd

我们知道很早之前的 Docker Engine 中就有了 containerd,只不过现在是将 containerd 从 Docker Engine 里分离出来,作为一个独立的开源项目,目标是提供一个更加开放、稳定的容器运行基础设施。分离出来的 containerd 将具有更多的功能,涵盖整个容器运行时管理的所有需求,提供更强大的支持。

containerd 是一个工业级标准的容器运行时,它强调简单性健壮性可移植性,containerd 可以负责干下面这些事情:

  • 管理容器的生命周期(从创建容器到销毁容器)
  • 拉取 / 推送容器镜像
  • 存储管理(管理镜像及容器数据的存储)
  • 调用 runc 运行容器(与 runc 等容器运行时交互)
  • 管理容器网络接口及网络


容器运行时环境还是使用大家熟知的 Docker,只是在 k8s v1.24 以后需要额外安装 cri-dockerd, k8s 才能够正常识别到 Docker。这里也可以使用其它容器运行时工具,比如 containerd, CRI-O 等可以根据个人喜好使用,只是截至目前 Docker 在国内占的比重依然可以说是一枝独秀



标签:容器,containerd,runc,Docker,CRI,运行
From: https://blog.51cto.com/first01/7910649

相关文章

  • 初学Bokeh:运行机制【3】跬步
    初学Bokeh:运行机制【3】跬步Bokeh的使用非常简单,通常仅需要几行Python代码,就可以创建出基于web浏览器的交互式、支持javascript的数据可视化效果。实现Bokeh数据可视化通常只需要两个步骤:从Bokeh的已有模块中选择创建你的数据可视化;定制这些模块以满足自身的需求;为了实现数......
  • 请在课上练习的基础上,实现输出加减法混合的运算题目列表。请提交代码及运行效果截图。
    importjava.util.Random;publicclassMathOperationGenerator{  publicstaticvoidmain(String[]args){    intnumberOfQuestions=10;//指定生成题目的数量    generateMathQuestions(numberOfQuestions);  }  publicstaticvoidgenerateMat......
  • 请完善课上的口算题卡代码,实现重复题目的检测、题目数字范围、加减乘除算式的参数化等
    importjava.util.HashSet;importjava.util.Random;importjava.util.Set;publicclassMathQuizGenerator{  publicstaticvoidmain(String[]args){    intnumberOfQuestions=10;//设定生成题目的数量    intminNumber=1;//题目数字的最小值 ......
  • Spark入门运行wordcount
    在spark集群上跑一个程序首先保证下面进程开启zookeeperhdfsspark首先是父类的依赖<properties><scala.version>2.11.8</scala.version><spark.version>2.2.2</spark.version><hadoop.version>2.7.6</hadoop.version></pro......
  • 小程序容器对比:优势与劣势
    继谷歌之后,2020年Apple也终于推出了AppClips。目标是借由提供轻量化App,省去下载原生App的麻烦,让用户先体验部分功能,以及融入各种消费场景,从而为原生App引流。尽管承载了极客们无数的期待,但AppClips的表现却不尽如人意,至今并未在市场激起任何水花。国内的小程序也好,......
  • docker 交互式运行容器的方法
    3.交互式运行容器的方法:dockerrun-itcentos每创建一个容器都是在之前的image之上多了一层,比如dockerrun了二次,每一次会基于这个镜像加了一层.所以,在查看contrainer时,会有两个容器.4.命令说明:docker分为ManagementCommands和Commands两种命令.#1.删除某个容器docke......
  • 关于crontab运行脚本时报错KeyError: 'PATH'
    最近在服务器上为let'sencrypt证书添加自动续签计划任务时,发现总是不成功,但手动执行该计划任务所对应的sh脚本则没问题,这让我怀疑crontab执行时可能缺少了点什么导致的,想追踪一下crontab的执行日志,发现并没有,需要手动修改配置文件打开:sudovim/etc/rsyslog.d/50-default.conf......
  • java学习第一天-安装JDK,运行Hello.java
    卸载JDK删除java的安装目录删除JAVA_HOME删除path下关于java的目录cmd下输入java-version安装JDK华为云JDK下载链接,首先下载JDK下载对应版本安装JDK设置安装路径配置环境变量打开环境变量新建系统变量-->JAVA_HOME配置path变量,新建%JAVA_......
  • 如何将没有复制或移动构造函数的对象放入vector容器
    正文直接说答案,这个问题无法实现。原因是因为std::vector容器的插入一定会调用类对象的构造函数或者移动构造函数。说一下为什么会有这个问题,因为不想用指针,我想直接通过类对象本身的RAII机制来实现的资源的控制,智能指针是一个解决方案,不过智能指针是写起来很繁琐,终究比不上值类......
  • Linux保持程序后台运行
    nohup命令(nohangup)nohup{someprogram}&&:让程序在后台运行nohup:在当前目录自动生成nohup.out,可以不挂断地运行命令当前用户非正常退出或结束的时候,命令仍然可能自己结束。因此使用了nohup的情况下,退出终端的时候需要使用exit才能保证命令一直在后台运行后台程......