在捕鱼大亨网络版中引入容器运行时接口(CRI)

编者注:这篇文章是 系列深入文章 捕鱼大亨网络版 1.5的新功能

在捕鱼大亨网络版节点的最低层是启动和停止容器的软件。我们称其为“容器运行时”。最广为人知的容器运行时是Docker,但在这个领域并不孤单。实际上,容器运行时空间正在迅速发展。为了使捕鱼大亨网络版具有更好的可扩展性,我们一直在研究一种新的插件API,用于捕鱼大亨网络版中的容器运行时,称为“ CRI”。

什么是CRI?为什么捕鱼大亨网络版需要它?

每个容器运行时都有自己的优势,许多用户要求捕鱼大亨网络版支持更多运行时。在捕鱼大亨网络版 1.5版本中,我们很自豪地介绍了 容器运行时界面 (CRI)-一个插件接口,使kubelet可以使用各种容器运行时,而无需重新编译。 CRI由 协议缓冲区gRPC API 图书馆,并且正在积极开发其他规范和工具。 CRI作为Alpha在 捕鱼大亨网络版 1.5.

在捕鱼大亨网络版中,支持可互换的容器运行时并不是一个新概念。在1.3版本中,我们宣布了 网络 项目启用 rkt集装箱发动机 替代Docker容器运行时。但是,Docker和rkt都通过内部易失的接口直接深入地集成到了kubelet源代码中。这样的集成过程需要对Kubelet内部的深刻理解,并给捕鱼大亨网络版社区带来大量的维护开销。这些因素构成了新生容器运行时进入的高度障碍。通过提供明确定义的抽象层,我们消除了障碍,并使开发人员可以专注于构建其容器运行时。这是迈向真正启用可插拔容器运行时和构建更健康的生态系统的一个很小但重要的步骤。

CRI概述
Kubelet使用gRPC框架通过Unix套接字与容器运行时(或运行时的CRI垫片)进行通信,其中kubelet充当客户端,而CRI垫片充当服务器。

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

service RuntimeService {

    // Sandbox operations.

    rpc RunPodSandbox(RunPodSandboxRequest) returns (RunPodSandboxResponse) {}  
    rpc StopPodSandbox(StopPodSandboxRequest) returns (StopPodSandboxResponse) {}  
    rpc RemovePodSandbox(RemovePodSandboxRequest) returns (RemovePodSandboxResponse) {}  
    rpc 荚SandboxStatus(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) {}

    ...  
}

荚由具有资源限制的隔离环境中的一组应用程序容器组成。在CRI中,此环境称为PodSandbox。我们有意留出一些空间让容器运行时根据PodSandbox内部运行方式来不同地解释PodSandbox。对于基于虚拟机监控程序的运行时,PodSandbox可能代表虚拟机。对于其他应用程序(例如Docker),它可能是Linux名称空间。 荚Sandbox必须遵守Pod资源规范。在v1alpha1 API 中,这是通过启动kubelet创建并传递到运行时的pod级cgroup中的所有进程来实现的。

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

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

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

捕鱼大亨网络版的声明性API带有 资源。我们考虑过的一种可能的设计是让CRI重用声明式 对象的抽象,使容器运行时可以自由实现和行使自己的控制逻辑以实现所需的状态。这将大大简化API,并允许CRI与更广泛的运行时一起使用。我们在设计初期就讨论了这种方法,并出于以下几个原因决定不采用这种方法。首先,kubelet中有许多Pod级别的功能和特定的机制(例如,崩溃循环后退逻辑),这对于所有运行时重新实现都是很大的负担。其次,更重要的是,Pod规范仍在(并且正在)迅速发展。只要kubelet直接管理容器,许多新功能(例如init容器)就不需要对基础容器运行时进行任何更改。 CRI采用命令式容器级接口,以便运行时可以共享这些通用功能,以提高开发速度。这并不意味着我们会偏离“级别触发”的哲学-kubelet负责确保实际状态被驱动为声明状态。

执行/附加/端口转发请求

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 荚Sandbox.  
    rpc PortForward(PortForwardRequest) returns (PortForwardResponse) {}

    ...  
}

捕鱼大亨网络版提供了一些功能(例如kubectl exec / attach / port-forward)供用户与Pod和其中的容器进行交互。今天,Kubelet通过调用容器运行时的本机方法调用或使用节点上可用的工具(例如nsenter和socat)来支持这些功能。在节点上使用工具不是一种可移植的解决方案,因为大多数工具都假定使用Linux名称空间将Pod隔离开来。在CRI中,我们在API中明确定义了这些调用以允许特定于运行时的实现。

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

CRI还有许多其他方面未在此博客文章中讨论。请参阅清单 设计文档和建议 对于所有细节。

当前状态

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

如果您有兴趣尝试这些替代运行时,则可以遵循各个存储库以获取最新进度和说明。

对于有兴趣集成新容器运行时的开发人员,请参阅 开发者指南 有关API的已知限制和问题。我们正在积极吸收早期开发人员的反馈意见,以改进API。开发人员应该期望偶尔的API重大更改(毕竟是Alpha)。

尝试新的CRI-Docker集成

默认情况下,Kubelet尚未使用CRI,但我们正在积极努力实现这一目标。第一步是使用CRI将Docker与kubelet重新集成。在1.5版本中,我们扩展了kubelet以支持CRI,并且还为Docker添加了内置的CRI垫片。这允许kubelet代表Docker启动gRPC服务器。要尝试新的kubelet-CRI-Docker集成,您只需使用--feature-gates = StreamingProxyRedirects = true启动捕鱼大亨网络版 API 服务器即可启用新的流重定向功能,然后使用--experimental-cri启动kubelet。 = true。

除了一些 缺少功能,新的集成始终通过了主要的端到端测试。我们计划尽快扩大测试范围,并希望鼓励社区报告任何问题以帮助过渡。

Minikube的CRI

如果您想尝试新的集成,但还没有时间在云中启动新的测试集群, 迷你库 是快速启动本地集群的好工具。开始之前,请按照 指示 下载并安装minikube。

  1. 检查可用的捕鱼大亨网络版版本并选择可用的最新1.5.x版本。我们将以v1.5.0-beta.1为例。
$ 迷你库 get-k8s-versions
  1. 使用内置的Docker CRI集成启动minikube集群。
$ 迷你库 start --kubernetes-version=v1.5.0-beta.1 --extra-config=kubelet.EnableCRI=true --network-plugin=kubenet --extra-config=kubelet.PodCIDR=10.180.1.0/24 --iso-url=http://storage.googleapis.com/minikube/iso/buildroot/minikube-v0.0.6.iso

--extra-config = kubelet.EnableCRI = true`打开kubelet中的CRI实现。 --network-plugin = kubenet和--extra-config = kubelet.PodCIDR = 10.180.1.0 / 24将网络插件设置为kubenet并确保将PodCIDR分配给该节点。或者,您可以使用不依赖PodCIDR的cni插件。 --iso-url为minikube设置一个iso映像以启动节点。示例中使用的图像

  1. 检查minikube日志以检查是否已启用CRI。
$ 迷你库 logs | grep EnableCRI

I1209 01:48:51.150789    3226 localkube.go:116] Setting EnableCRI to true on kubelet.
  1. 创建一个窗格并检查其状态。您应该看到“ SandboxReceived”事件,以证明Kubelet正在使用CRI!
$ kubectl run foo --image=gcr.io/google\_containers/pause-amd64:3.0

deployment "foo" created

$ kubectl describe pod foo

...

... From                Type   Reason          Message  
... -----------------   -----  --------------- -----------------------------

...{default-scheduler } Normal Scheduled       Successfully assigned foo-141968229-v1op9 to 迷你库  
...{kubelet 迷你库}   Normal SandboxReceived 荚 sandbox received, it will be created.

...

_注意,在minikube中启用CRI时,kubectl attach / exec / port-forward尚不起作用,但这 将在更新的minikube版本中解决。 _

社区

捕鱼大亨网络版正在积极开发和维护CRI SIG节点 社区。我们希望收到您的反馈。要加入社区:

-Yuu-Ju Hong,Google软件工程师