k8s-容器运行时接口分析

1、为了什么需要 CRI ?

在 k8s v1.5 之前,Docker 作为第一代的容器运行时, kubelet 通过内嵌其中的 DockerShim 操作 Docker API 来操作容器。在 Kubernetes 1.5 中引入了 CRI,可以解耦了kubelet与容器运行时,该插件接口让 Kubernetes 无需重新编译就可以支持更多的容器运行时。

kubelet 将通过 CRI 接口来跟第三方容器运行时进行通信(如Rkt或Hyper等),来操作容器与镜像。CRI 包含 Protocol Buffers、gRPC API、以及运行库支持,还有尚在开发的标准规范和工具。

2、CRI 概览

实现 CRI 接口的容器运行时称为 CRI shim , 它作为 gRPC 服务端,监听在本地的 Unix socket 上;而 Kubelet 作为 gRPC 客户端来调用 CRI 接口,进行 Pod 、容器、镜像的生命周期管理。

Protocol Buffers API 包含两个 gRPC 服务 ImageServiceRuntimeService

  • ImageService 提供从仓库拉取镜像、查看和移除镜像等功能;
  • RuntimeService 提供对 Pod 和容器的生命周期管理、和容器的交互,创建和启动容器、删除容器等功能;

另外安装时,需要在每台宿主机上单独安装一个负责响应 CRI 的组件称作 CRI shim。顾名思义,CRI shim 的工作,就是扮演 kubelet 与容器项目之间的"垫片"(shim)。所以它的作用非常单一,那就是实现 CRI 规定的每个接口,然后把具体的 CRI 请求"翻译"成对后端容器项目的请求或者操作。

3、Pod 和容器的生命周期管理

go 复制代码
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 可能代表虚拟机。对于其他人,例如Docker,它可能是Linux命名空间。PodSandbox 必须遵守 Pod 资源规范。在 v1alpha1 API 中,这是通过启动 kubelet 创建并传递给运行时的 pod 级 cgroup 中的所有进程来实现的。

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

Kubelet 的职责在于通过 RPC 管理容器的生命周期,实现容器生命周期的钩子,以及存活和健康监测,执行 Pod 的重启策略等。

4、Exec/attach/port-forward 请求

go 复制代码
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 为用户提供了和 Pod 以及其中的容器进行交互的能力(kubectl exec/attach/port-forward)。Kubelet 目前支持两种方式来支持这些功能:调用容器的本地方法,或者使用 Node 上的工具(例如 nsenter 以及 socat)。因为多数工具假设 Pod 利用 Linux namespace 做了隔离,因此使用 Node 上的工具并不是一个可移植的方案。在 CRI 中,我们显式的定义这些调用,让运行时可以做特定实现。

当下还有一个潜在问题是,Kubelet 处理所有的请求连接,所以他有成为 Node 通信瓶颈的可能。在设计 CRI 的时候,我们采纳了一些反馈,让运行时能够排除中间人。容器运行时可以启动一个单独的流服务器处理请求(还能为 Pod 的资源使用进行记录),并把服务器地址返回给 Kubelet。这样 Kubelet 就能反馈信息给 API Server,使之可以直接连接到容器运行时的服务,并连接到客户端。

相关推荐
ShareBeHappy_Qin24 分钟前
ZooKeeper 中的 ZAB 一致性协议与 Zookeeper 设计目的、使用场景、相关概念(数据模型、myid、事务 ID、版本、监听器、ACL、角色)
分布式·zookeeper·云原生
颜淡慕潇4 小时前
【K8S系列】在 K8S 中使用 Values 文件定制不同环境下的应用配置
云原生·容器·kubernetes·环境配置
旦沐已成舟4 小时前
K8S-Pod的环境变量,重启策略,数据持久化,资源限制
java·docker·kubernetes
github_czy4 小时前
(k8s)k8s部署mysql与redis(无坑版)
redis·容器·kubernetes
超级阿飞4 小时前
利用Kubespray安装生产环境的k8s集群-实施篇
elasticsearch·容器·kubernetes
来恩100311 小时前
Kubernetes学习指南与资料分享
云原生·容器·kubernetes
encoding-console12 小时前
docker安装consul并启动的详细步骤
docker·容器·consul
m0_7482299913 小时前
从零到上线:Node.js 项目的完整部署流程(包含 Docker 和 CICD)
docker·容器·node.js
weixin_3875456415 小时前
探索云原生可观测性:技术与团队协作的深度结合
云原生
_Eden_17 小时前
Docker入门学习
学习·docker·容器