containerd中文翻译系列(二十二)运行时v2

这篇具有很好参考价值的文章主要介绍了containerd中文翻译系列(二十二)运行时v2。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Runtime v2 为运行时作者集成 containerd 引入了一级 shim API。

containerd 作为守护进程,并不直接启动容器。相反,它充当更高级别的管理器
或枢纽的作用,以协调容器和内容的活动。被称作 "运行时"的程序真正来启动、停止和管理容器、无论是单个容器还是容器组(如 Kubernetes pods)。

例如,containerd 会检索容器镜像配置及其作为层的内容,使用快照器将其放置在磁盘上,设置容器的 rootfs 和配置,然后启动一个运行时来创建/启动/停止容器。

本文档介绍了 v2 运行时集成模型的主要组件,以及这些组件如何与 containerd 和 v2 运行时交互。以及如何使用和集成不同的 v2 运行时。

为了简化交互,v2 版运行时引入了第一类 v2 API,供运行时作者与 containerd 集成、取代了 v1 API。
v2 API 是最小的,其作用域仅限于容器的执行生命周期。

本文档分为以下几个部分:

  • 架构](#architecture) - 主要组件、它们的用途和关系
  • 用法](#usage) - 如何调用特定运行时,以及如何配置它们
  • 编写](#shim-authoring) - 如何编写 v2 运行时

架构

containerd与运行时通信

containerd 希望运行时能实现几种容器控制功能,如创建、启动和停止。

高级流程如下:

客户端请求 containerd 创建一个容器
containerd 布局容器的文件系统,并创建必要的配置信息
containerd 通过 API 调用运行时来创建/启动/停止容器

不过,containerd 本身实际上并不直接调用运行时来启动容器。相反,它希望调用运行时,运行时将暴露一个套接字(在类 Unix 系统上是 Unix Domain,在Windows 系统上是命名为管道的套接字),并通过 ttRPC 在该套接字上监听容器命令。

运行时将处理这些操作。至于如何处理,则完全取决于运行时的实现。
两种常见的模式是

  • 运行时使用一个二进制文件,既监听套接字,又创建/启动/停止容器
  • 一个单独的临时二进制文件,它监听套接字,并调用一个单独的运行时引擎来创建/启动/停止容器

现在采用的是分离的 "shim+engine "模式,这样可以更容易地集成执行特定运行时引擎规范(如OCI 运行时规范的不同运行时。

ttRPC协议可通过一个运行时垫片(shim)来处理,和不同的运行时引擎实现无关。只要它们实现的是 OCI 运行时规范。

最常用的运行时引擎是runc,它实现了OCI运行时规范。由于这是一个运行时引擎,它并不直接被containerd调用而是由 shim 来调用,shim 监听套接字并调用运行时引擎。

shim+engine 架构
运行时 shim

运行时 shim 实际上是由 containerd 调用的。除了提供 containerd 的通信端口和一些配置信息之外,它在启动时的选项极少。

运行时 shim 在套接字上监听来自 containerd 的 ttRPC 命令,然后调用一个单独的运行时引擎程序、通过 fork/exec 运行容器。例如,io.containerd.runc.v2 shim 会调用运行时引擎,如 runc

containerd 通过 ttRPC 连接向 shim 传递选项,其中可能包括要调用的运行时引擎二进制文件。这些是 [CreateTaskRequest](#container-level-shim-configuration)的选项

例如,io.containerd.runc.v2 shim 支持包含运行时引擎二进制文件的路径。

运行时引擎

运行时引擎本身是实际启动和停止容器的工具。

例如,在 runc 的情况下,containerd 项目提供的 shim作为可执行文件 "containerd-shim-runc-v2 "提供。它由 containerd 调用并启动 ttRPC 监听器。

然后,该shim调用实际的 runc 二进制文件,将容器配置传递给它,而 runc 二进制文件则通常通过 libcontainer->system apis 创建/启动/停止容器。

shim+engine 关系

由于每个 shim 实例都作为守护进程与 containerd 通信,同时通过调用独立的运行时来孕育容器、可以用一个 shim 来管理多个容器和调用。例如一个 containerd-shim-runc-v2 与一个 containerd 通信,它可以调用十个不同的容器。

甚至还可以为多个容器设置一个 shim,每个容器都有自己的实际运行时、因为如上所述,运行时二进制文件是作为 CreateTaskRequest 中的选项之一传递的。

containerd 不知道也不关心 shim 与容器的关系是一对一还是一对多。这完全由 shim 决定。例如,io.containerd.runc.v2 shim会根据是否存在标签分组。在实践中,这意味着由 Kubernetes 启动的、属于同一个 Kubernetes pod 的容器,将由单个shim处理,并根据 CRI 插件设置的 "io.kubernetes.cri.sandbox-id "标签分组。

流程如下

  1. containerd 接收到创建容器的请求
  2. containerd 布局容器的文件系统,并创建必要的 container config 信息
  3. containerd 调用 shim,包括容器配置,它使用这些信息来决定是启动一个新的套接字监听器(1:1 shim 到容器),还是使用一个现有的套接字监听器(1:多个)
    • 如果是已经存在,则返回现有套接字的地址并退出
    • 如果是新的套接字监听器,shim将
      1. 创建一个新进程,通过套接字监听containerd发出的 ttRPC 命令
      2. 将该套接字的地址返回给containerd并退出,向shim发送启动容器的命令
  4. shim 调用 runc 来创建/启动/停止容器

本文档后面的 流程中提供了一个很好的流程图。

使用方法

调用运行时

创建容器时,可以选择运行时-单实例或 shim+engine 运行时-及其选项。
containerd服务(containerd客户端、CRI API…),或通过调用containerd提供服务的客户端来户端的例子包括 ctrnerdctl、kubernetes、docker/moby、rancher 等。

运行时也可以通过容器更新来更改。

传递的运行时名称是一个字符串,用于向 containerd 标识运行时。如果是单独的 shim+engine,那么这个字符串就是运行时 shim。无论如何,这都是 containerd 执行并期望启动 ttRPC 监听器的二进制文件。
运行时名称可以是类似 URI 的字符串,或者从 containerd 1.6.0 开始是可执行文件的实际路径。

  1. 如果运行时名称是一个路径,则使用它作为要调用的运行时的实际路径。
  2. 如果运行时名称类似 URI,则按以下逻辑将其转换为运行时名称。

如果运行时名称是 URI-like,containerd 将使用下面的逻辑把传递的运行时从 URI-like名称转换为二进制名称:

  1. - 替换所有 .
  2. 取最后 2 个成分,例如 runc.v2 .
  3. containerd-shim 为前缀

例如,如果运行时名称是 io.containerd.runc.v2, containerd 将以 containerd-shim-runc-v2 的形式调用 shim。并期望能在正常的PATH路径上找到这个名称的二进制文件。

containerd 保留了 containerd-shim-* 前缀,这样用户就可以 ps aux | grep containerd-shim查看系统中正在运行的 shim。

例如

$ ctr --runtime io.containerd.runc.v2 run --rm docker.io/library/alpine:latest alpine

将调用 containerd-shim-runc-v2

您可以尝试使用其他名称来测试:

$ ctr run --runtime=io.foo.bar.runc2.v2.baz --rm docker.io/library/hello-world:latest hello-world /hello
ctr: failed to start shim: failed to resolve runtime path: runtime "io.foo.bar.runc2.v2.baz" binary not installed "containerd-shim-v2-baz": file does not exist: unknown

它接收到 io.foo.bar.runc2.v2.baz 并查找 containerd-shim-v2-baz

你还可以通过传递 --runc-binary 选项,覆盖为 shim 配置的默认运行时选项。例如"

ctr --runtime io.containerd.runc.v2 --runc-binary /usr/local/bin/runc-custom run --rm docker.io/library/alpine:latest alpine

配置运行时

您可以在 containerd 的 config.toml 配置文件中配置一个或多个运行时,方法是修改下面的部分:

      [plugins."io.containerd.grpc.v1.cri".containerd.runtimes]

更多详情和示例请参阅 config.toml man page。

配置文件中的这些 "命名运行时 "仅在通过 CRI 调用时使用。
它有一个runtime_handler字段。

shim 作者

本节专为希望创建 Shim 的运行时作者而设。
它将详细介绍 API 的工作原理以及构建 shim 时的不同注意事项。

命令

容器信息通过两种方式提供给 shim。
OCI Runtime Bundle和 Create rpc 请求。

start 启动

每个 shim 必须实现一个 start 子命令。
该命令将启动新的 shim。
启动命令必须接受以下标志:

  • -namespace 容器的命名空间
  • -address containerd 的主 grpc socket 地址
  • 向容器 ID 发布事件的二进制路径
  • -id 容器的 ID

启动命令以及对 shim 的所有二进制调用都将容器的 bundle 设置为 cwd

start 命令可能有以下特定于 containerd 的环境变量设置:

  • containerd 的 ttrpc API 套接字地址
  • GRPC_ADDRESS containerd 的 grpc API 套接字(1.7 及以上版本)的地址
  • MAX_SHIM_VERSION 客户端支持的最大 shim 版本,总是 2 表示 shim v2 (1.7+)
  • SCHED_CORE 启用内核调度(如果可用) (1.6+)
  • NAMESPACE 一个可选的命名空间,Shim 在其中运行或继承该命名空间 (1.7+)

启动命令必须向 stdout 写入 shim 为其 API 服务的 ttrpc 地址,或者 (实验性的)
格式的 JSON 结构(其中协议可以是 "ttrpc "或 “grpc”):

{
	"version": 2,
	"address": "/address/of/task/service",
	"protocol": "grpc"
}

该地址将被 containerd 用来发出容器操作的 API 请求。

start 命令既可以启动一个新的 shim,也可以根据 shim 的逻辑将地址返回给现有的 shim。

delete

每个 shim 必须实现一个 delete 子命令。当 containerd 无法再通过 rpc 通信时,该命令允许 containerd 删除由 shim 创建、挂载和/或运行的任何容器资源。如果 shim 与运行中的容器一起被 SIGKILL,就会发生这种情况。当 containerd 失去与 shim 的连接时,将需要清理这些资源。这也会在 containerd 启动并重新连接到 shim 时使用。如果 bundle 仍在磁盘上,但 containerd 无法连接到 shim,则会调用删除命令。

删除命令必须接受以下标志:

  • 容器的命名空间
  • -address containerd 的主套接字地址
  • 向容器 ID 发布事件的二进制路径
  • -id 容器的ID
  • bundle 要删除的 bundle 的路径。在非 Windows 和非 FreeBSD 平台上,这将与 cwd 匹配。

除 Windows 和 FreeBSD 平台外,删除命令将在容器的捆绑包中作为其 cwd 执行。

类似命令的标志

-v

每个 shim 都应该执行一个 -v 标志。
这个类似命令的标志会打印 shim 实现的版本并退出。
输出结果不可用机器解析。

-info.

每个 shim 都应该执行一个 -info 标志。
这个类似于命令的标志会从 stdin 获取选项 protobuf,并打印 shim info protobuf(见下文)到 stdout,然后退出。

message RuntimeInfo {
       string name = 1;
       RuntimeVersion version = 2;
       // Options from stdin
       google.protobuf.Any options = 3;
       // OCI-compatible runtimes should use https://github.com/opencontainers/runtime-spec/blob/main/features.md
       google.protobuf.Any features = 4;
       // Annotations of the shim. Irrelevant to features.Annotations.
       map<string, string> annotations = 5;
}

主机级垫片配置

containerd 不会通过 API 为临时部件提供任何主机级配置。
如果一个 shim 需要用户在所有实例中提供主机级别的配置信息,可以设置一个 shim 特定的配置文件。

容器级垫片配置

在创建请求中,有一个通用的 *protobuf.Any 允许用户为 shim 指定容器级配置。

message CreateTaskRequest {
	string id = 1;
	...
	google.protobuf.Any options = 10;
}

shim 作者可以为配置创建自己的 protobuf 信息,客户端可以根据需要导入并提供这些信息。

I/O

容器的 I/O 由客户端通过 Linux 上的 fifo、Windows 上的命名管道或磁盘上的日志文件提供给 shim。这些文件的路径会在初始创建的 Create rpc 和附加进程的 Exec rpc 中提供。

message CreateTaskRequest {
	string id = 1;
	bool terminal = 4;
	string stdin = 5;
	string stdout = 6;
	string stderr = 7;
}
message ExecProcessRequest {
	string id = 1;
	string exec_id = 2;
	bool terminal = 3;
	string stdin = 4;
	string stdout = 5;
	string stderr = 6;
}

使用交互式终端启动的容器将把 terminal 字段设置为 true,数据仍会以与非交互式容器相同的方式复制到文件(fifos、管道)上。

根文件系统

容器的根文件系统由 Create rpc 提供。在容器的生命周期中,Shims 负责管理文件系统挂载的生命周期。

message CreateTaskRequest {
	string id = 1;
	string bundle = 2;
	repeated containerd.types.Mount rootfs = 3;
	...
}

挂载 protobuf 信息是

message Mount {
	// 类型定义挂载的性质。
	string type = 1;
	// 源指定挂载的名称。根据挂载类型,这
	// 可以是卷名或主机路径,甚至可以忽略。
	string source = 2;
	// 容器中的目标路径
	string target = 3;
	//选项指定零个或多个 fstab 样式的挂载选项。
	repeated string options = 4;
}

Shims 负责将文件系统挂载到 bundle 的 rootfs/ 目录中。shims还负责卸载文件系统。在delete二进制调用期间,shims必须确保文件系统也被卸载。文件系统由 containerd 快照程序提供。

事件

运行时 v2 支持异步事件模型。为了让上游调用者(如 Docker)以正确的顺序获取这些事件,Runtime v2 shim 必须实现以下事件(其中 Compliance=MUST)。这就避免了 shim 和 shim 客户端之间的竞赛条件,例如,对 Start 的调用会在返回 Start 调用的结果之前发出 TaskExitEventTopic 信号。有了 Runtime v2 shim 的这些保证,在 shim 发布TaskExitEventTopic之前,Start调用必须已发布异步事件TaskStartEventTopic

任务
主题 合规性 说明
runtime.TaskCreateEventTopic MUST 任务被成功启动时
runtime.TaskStartEventTopic MUST (follow TaskCreateEventTopic) 任务被成功启动时
runtime.TaskExitEventTopic MUST (follow TaskStartEventTopic) 任务按预期或意外退出时
runtime.TaskDeleteEventTopic MUST (follow TaskExitEventTopic or TaskCreateEventTopic 如果已启动) 任务从shim中删除时
runtime.TaskPausedEventTopic SHOULD 任务被成功暂停时
runtime.TaskResumedEventTopic SHOULD (follow TaskPausedEventTopic) 任务被成功回复时
runtime.TaskCheckpointedEventTopic SHOULD 任务被检查点时
runtime.TaskOOMEventTopic SHOULD 如果闪存收集到 "内存不足 "事件
Execs
主题 合规 描述
runtime.TaskExecAddedEventTopic MUST (follow TaskCreateEventTopic ) exec被成功添加时
runtime.TaskExecStartedEventTopic MUST (follow TaskExecAddedEventTopic) exec被成功启动时
runtime.TaskExitEventTopic MUST (follow TaskExecStartedEventTopic) 当执行程序(除初始执行程序外)在预期或意外情况下退出时
runtime.TaskDeleteEventTopic SHOULD (follow TaskExitEventTopic or TaskExecAddedEventTopic 从未启动过) 当执行程序从shim中移除时
流程

下面的序列图显示了执行 ctr run 命令时的操作流程。

日志

Shims 可通过 STDIO URI 支持可插入的日志记录。
目前支持的日志记录方案有

  • fifo - Linux
  • 二进制 - Linux 和 Windows
  • 文件 - Linux 和 Windows
  • npipe - Windows

二进制日志记录能够将容器的 STDIO 转发到外部二进制文件以供使用。
将容器的 STDOUT 和 STDERR 转发到 journald 的日志记录驱动示例如下:

package main

import (
	"bufio"
	"context"
	"fmt"
	"io"
	"sync"

	"github.com/containerd/containerd/v2/core/runtime/v2/logging"
	"github.com/coreos/go-systemd/journal"
)

func main() {
	logging.Run(log)
}

func log(ctx context.Context, config *logging.Config, ready func() error) error {
	// construct any log metadata for the container
	vars := map[string]string{
		"SYSLOG_IDENTIFIER": fmt.Sprintf("%s:%s", config.Namespace, config.ID),
	}
	var wg sync.WaitGroup
	wg.Add(2)
	// forward both stdout and stderr to the journal
	go copy(&wg, config.Stdout, journal.PriInfo, vars)
	go copy(&wg, config.Stderr, journal.PriErr, vars)

	// signal that we are ready and setup for the container to be started
	if err := ready(); err != nil {
		return err
	}
	wg.Wait()
	return nil
}

func copy(wg *sync.WaitGroup, r io.Reader, pri journal.Priority, vars map[string]string) {
	defer wg.Done()
	s := bufio.NewScanner(r)
	for s.Scan() {
		journal.Send(s.Text(), pri, vars)
	}
}

其他

不支持的 rpcs

如果 Shim 没有或无法实现 rpc 调用,则必须返回 github.com/containerd/containerd/errdefs.ErrNotImplemented 错误。

调试和 Shim 日志

unix 上的 fifo 或 Windows 上的命名管道将提供给 shim。它可以位于 shim 的 cwd 中,名为 “log”。shims 可以使用现有的 github.com/containerd/log 软件包来记录调试信息。信息会自动在容器 d 的守护进程日志中输出,并设置正确的字段和运行时间。

ttrpc

ttrpc是垫片支持的协议之一。像生成客户端一样,它可与标准 protobufs 和 GRPC 服务一起使用。grpc 和 ttrpc 之间的唯一区别是wire协议。ttrpc 删除了 http 栈,以节省内存和二进制文件大小,从而保持较小的shim。建议在你的 shim 中使用 ttrpc,但 grpc 支持目前只是一个实验性功能。文章来源地址https://www.toymoban.com/news/detail-825755.html

到了这里,关于containerd中文翻译系列(二十二)运行时v2的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 云计算实战系列二十二(Python编程I)_pypy 扫描依赖包(1)

    先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7 深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前! 因此收集整理了一份《2024年最新网络安全全套学习资料》

    2024年04月22日
    浏览(35)
  • 【云原生 | Kubernetes 系列】— 部署K8S 1.28版本集群部署(基于Containerd容器运行)

    主机名 IP地址 备注 k8s-master01 192.168.0.109 master k8s-node1 192.168.0.108 node1 k8s-node2 192.168.0.107 node1 k8s-node3 192.168.0.105 node1 1、主机配置 2、升级内核 3、配置内核转发以及过滤 4、安装ipset ipvsadm,IPVS(IP Virtual Server)是一个用于负载均衡的 Linux 内核模块,它可以用来替代 kube-proxy 默认的

    2024年02月20日
    浏览(85)
  • 第二章:25+ Python 数据操作教程(第二十二节如何从 R 调用或运行 python)持续更新

    本文介绍了如何从 R 调用或运行 python。这两种工具都有自己的优点和缺点。使用这两个工具中最好的包和功能并将其组合起来总是一个好主意。在数据科学领域,这些工具在使用方面拥有良好的市场份额。R 主要以数据分析、统计建模和可视化而闻名。而Python在深度学习和自

    2024年02月07日
    浏览(58)
  • 【SQL开发实战技巧】系列(二十二):数仓报表场景☞ 从分析函数效率一定快吗聊一聊结果集分页和隔行抽样实现方式

    【SQL开发实战技巧】系列(一):关于SQL不得不说的那些事 【SQL开发实战技巧】系列(二):简单单表查询 【SQL开发实战技巧】系列(三):SQL排序的那些事 【SQL开发实战技巧】系列(四):从执行计划讨论UNION ALL与空字符串UNION与OR的使用注意事项 【SQL开发实战技巧】系列

    2024年02月02日
    浏览(54)
  • C++学习笔记(二十二)

    概念: 重载函数调用操作符的类,其对象常称为函数对象 函数对象使用重载的 () 时,行为类似函数调用,也叫仿函数 本质: 函数对象(仿函数)是一个类,不是一个函数 特点: 函数对象在使用时,可以像普通函数那样调用,可以有参数,可以有返回值 函数对象超出普通函数

    2024年01月18日
    浏览(60)
  • 第二十二章 光照贴图

    光照贴图过程将预先计算场景中静态物体表面的亮度,并将结果存储在称为“光照贴图”的纹理中供以后使用。光照贴图可以包含直接光照和间接光照,以及阴影效果。但是,烘焙到光照贴图中的数据无法在运行时更改,这就是为什么移动静态物体后,阴影不会跟随移动。接

    2024年02月02日
    浏览(46)
  • 量子计算(二十二):Grover算法

    文章目录 Grover算法 一、什么是搜索算法  二、怎么实现Grover搜索算法 举一个简单的例子,在下班的高峰期,要从公司回到家里,开车走怎样的路线才能够耗时最短呢?最简单的想法,当然是把所有可能的路线一次一次的计算,根据路况计算每条路线所消耗的时间,最终可以

    2024年02月02日
    浏览(38)
  • Android——数据存储(二)(二十二)

    1.1 知识点 (1)了解SQLite数据库的基本作用; (2)掌握数据库操作辅助类:SQLiteDatabase的使用; (3)可以使用命令操作SQLite数据库; (4)可以完成数据库的CRUD操作; (5)掌握数据库查询及Cursor接口的使用。 1.2 具体内容 在Android当中,本身提供了一种微型的嵌入式数据库

    2024年02月09日
    浏览(36)
  • 设计模式(二十二)模板方法

    定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类不改变一个算法的结构即可重定义该算法的特定步骤。模板方法是一种类行为型模式 模板方法模式结构比较简单,其核心是抽象类和其中的模板方法的设计,包含以下两个角色: 1、AbstractClas

    2024年01月22日
    浏览(36)
  • opencv_c++学习(二十二)

    图中左侧为边缘检测的效果,中间为图像经过二值化的效果,右图为凸包检测效果。 points:输入的2D点集。 hull:输出凸包的顶点。 clockwise:方向标志,当参数为true时,凸包顺序为顺时针方向,否则为逆时针方向。 returnPoints:输出数据的类型标志,当参数为true时第二个参数输出的

    2024年02月06日
    浏览(70)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包