在Kubernetes中引入Container Runtime Interface (CRI)

找这方面的资料.看到所以翻译下

写在前面


傍晚时分,你坐在屋檐下,看着天慢慢地黑下去,心里寂寞而凄凉,感到自己的生命被剥夺了。当时我是个年轻人,但我害怕这样生活下去,衰老下去。在我看来,这是比死亡更可怕的事。——–王小波


Kubernetes节点的最低层启动和停止容器的软件。我们称之为“容器运行时”。最广为人知的容器运行时Docker,但它并不是唯一的容器运行时。事实上,容器运行时空间一直在快速发展。作为使Kubernetes更具可扩展性的努力的一部分,我们一直致力于Kubernetes中用于容器运行时的新插件API,称为“CRI”。

CRI是什么? Kubernetes为什么需要它?

每个容器运行时都有自己的优点,许多用户要求Kubernetes支持更多的运行时。在Kubernetes 1.5版本中,我们自豪地引入了容器运行时接口(CRI)——一个插件接口,它使kubelet能够使用各种各样的容器运行时,而不需要重新编译。CRI包括协议缓冲区、gRPC API和库,以及正在积极开发的其他规范和工具。CRI在Kubernetes 1.5中以Alpha版本发布。

在Kubernetes中,支持可互换的容器运行时并不是一个新概念。在1.3版本中,我们宣布了rktnetes项目,以启用rkt容器引擎作为Docker容器运行时的替代方案。然而,Docker和rkt都通过一个内部和易变的接口直接和深入地集成到kubelet源代码中。这样的集成过程需要对Kubelet的内部特性有深入的了解,并且会给Kubernetes社区带来巨大的维护开销。这些因素对新生的容器运行时形成了很高的进入壁垒。通过提供一个清晰定义的抽象层,我们消除了障碍,并允许开发人员专注于构建他们的容器运行时。这是迈向真正实现可插拔容器运行时和构建更健康的生态系统的一小步,但却是重要的一步。

Kubelet使用gRPC框架通过Unix套接字与容器运行时(或运行时的CRI shim)通信,其中Kubelet作为客户端,CRI shim作为服务器。

协议缓冲区API包括两个gRPC服务,ImageService和RuntimeService。ImageService提供了从存储库中提取图像、检查和删除图像的rpc。RuntimeService包含rpc来管理pod和容器的生命周期,以及与容器交互的调用(exec/attach/port-forward)。一个管理图像和容器的单片容器运行时(例如,Docker和rkt)可以通过一个套接字同时提供两个服务。套接字可以在Kubelet中通过——container-runtime-endpoint和——image-service-endpoint标志来设置。Pod和容器生命周期管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
service RuntimeService {

// Sandbox operations.

rpc RunPodSandbox(RunPodSandboxRequest) returns (RunPodSandboxResponse) {}
rpc StopPodSandbox(StopPodSandboxRequest) returns (StopPodSandboxResponse) {}
rpc RemovePodSandbox(RemovePodSandboxRequest) returns (RemovePodSandboxResponse) {}
rpc PodSandboxStatus(PodSandboxStatusRequest) returns (PodSandboxStatusResponse) {}
rpc ListPodSandbox(ListPodSandboxRequest) returns (ListPodSandboxResponse) {}

// Container operations.
rpc CreateContainer(CreateContainerRequest) returns (CreateContainerResponse) {}
rpc StartContainer(StartContainerRequest) returns (StartContainerResponse) {}
rpc StopContainer(StopContainerRequest) returns (StopContainerResponse) {}
rpc RemoveContainer(RemoveContainerRequest) returns (RemoveContainerResponse) {}
rpc ListContainers(ListContainersRequest) returns (ListContainersResponse) {}
rpc ContainerStatus(ContainerStatusRequest) returns (ContainerStatusResponse) {}

...
}

Pod由一组应用程序容器组成,它们位于具有资源约束的独立环境中。在CRI中,这个环境称为PodSandbox。我们有意为容器运行时留出一些空间,让它们根据PodSandbox内部的操作方式来不同地解释PodSandbox。对于基于管理程序的运行时,PodSandbox可能代表一个虚拟机。对于其他的,比如Docker,它可能是Linux名称空间。PodSandbox必须遵守pod资源规范。在v1alpha1 API中,这是通过启动kubelet创建并传递给运行时的pod级cgroup中的所有进程来实现的。

在启动一个pod之前,kubelet调用RuntimeService。RunPodSandbox来创建环境。这包括为pod设置网络(例如,分配IP)。一旦PodSandbox是活动的,就可以独立地创建/启动/停止/删除单个容器。要删除pod, kubelet将在停止并删除PodSandbox之前停止并删除容器。

Kubelet负责通过rpc管理容器的生命周期,执行容器生命周期钩子和活动/就绪检查,同时遵守pod的重启策略。

为什么必须使用以容器为中心的接口?

Kubernetes有一个带有Pod资源的声明性API。我们考虑的一种可能的设计是,让CRI在其抽象中重用声明性Pod对象,让容器运行时可以自由地实现和练习其自己的控制逻辑,以实现所需的状态。这将极大地简化API,并允许CRI在更广泛的运行时范围内工作。我们在设计阶段的早期就讨论了这种方法,并基于几个原因决定不采用它。首先,kubelet中有许多pod级别的特性和特定的机制(例如,崩溃循环回退逻辑),这将是所有运行时重新实现的重大负担。第二,也是更重要的,Pod规范过去(现在)仍在快速发展。许多新特性(例如init容器)不需要对底层容器运行时进行任何更改,只要kubelet直接管理容器即可。CRI采用了一个命定的容器级接口,这样运行时就可以共享这些公共特性,以获得更好的开发速度。这并不意味着我们偏离了“水平触发”的哲学——kubelet负责确保实际的状态被驱动到声明的状态。

执行/高度/左前请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
service RuntimeService {

...

// ExecSync runs a command in a container synchronously.
rpc ExecSync(ExecSyncRequest) returns (ExecSyncResponse) {}
// Exec prepares a streaming endpoint to execute a command in the container.
rpc Exec(ExecRequest) returns (ExecResponse) {}
// Attach prepares a streaming endpoint to attach to a running container.
rpc Attach(AttachRequest) returns (AttachResponse) {}
// PortForward prepares a streaming endpoint to forward ports from a PodSandbox.
rpc PortForward(PortForwardRequest) returns (PortForwardResponse) {}

...
}

Kubernetes提供了一些特性(例如kubectl exec/attach/port-forward),让用户可以与pod和其中的容器进行交互。Kubelet现在通过调用容器运行时的本地方法调用或使用节点上可用的工具(例如nsenter和socat)来支持这些特性。在节点上使用工具不是一个可移植的解决方案,因为大多数工具都假定pod是使用Linux名称空间隔离的。在CRI中,我们在API中显式地定义这些调用,以允许特定于运行时的实现。

目前kubelet实现的另一个潜在问题是,kubelet处理所有流请求的连接,因此它可能成为节点上网络流量的瓶颈。在设计CRI时,我们合并了这个反馈,以允许运行时消除中间人。容器运行时可以根据请求启动一个单独的流服务器(并可能将资源使用情况记录到pod中!),并将服务器的位置返回给kubelet。然后Kubelet将此信息返回给Kubernetes API服务器,该服务器将直接打开到运行时提供的服务器的流连接,并将其连接到客户端。

还有许多CRI的其他方面在这篇博文中没有涉及。所有细节请参阅设计文件和方案的列表。

当前的状态

尽管CRI仍处于早期阶段,但已经有几个项目在开发中使用CRI集成容器运行时。以下是一些例子:

  • cri-o: OCI conformant runtimes.
  • rktlet: the rkt container runtime.
  • frakti: hypervisor-based container runtimes.
  • docker CRI shim.


如果您有兴趣尝试这些可选的运行时,可以根据各个存储库了解最新的进度和说明。

对于有兴趣集成新的容器运行时的开发人员,请参阅开发人员指南,了解API的已知限制和问题。我们正在积极地整合早期开发人员的反馈,以改进API。开发人员应该期待偶尔的API破坏变化(毕竟是Alpha版本)。

尝试新的CRI-Docker集成

Kubelet在默认情况下还没有使用CRI,但我们正在积极努力实现这一点。第一步是使用CRI重新集成Docker和kubelet。在1.5版中,我们扩展了kubelet以支持CRI,并为Docker添加了一个内置CRI shim。这允许kubelet以Docker的名义启动gRPC服务器。要尝试新的kubelet- cri - docker集成,您只需使用——feature-gates=StreamingProxyRedirects=true启动Kubernetes API服务器,以启用新的流重定向特性,然后使用——experimental-cri=true启动kubelet。

除了一些缺失的特性外,新集成始终通过了主要的端到端测试。我们计划很快扩大测试覆盖范围,并鼓励社区报告任何问题,以帮助过渡。

发布于

2021-10-11

更新于

2023-06-21

许可协议

评论
Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×