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,使之可以直接连接到容器运行时的服务,并连接到客户端。

相关推荐
唯情于酒2 小时前
Docker学习
学习·docker·容器
喵叔哟3 小时前
20.部署与运维
运维·docker·容器·.net
广州服务器托管6 小时前
NVIDIA最新591.74显卡驱动精简版:支持DLSS 4.5、所有RTX显卡都可使用,最新N卡驱动下载
计算机网络·网络安全·云原生·个人开发·可信计算技术
运维栈记8 小时前
虚拟化网络的根基-网络命名空间
网络·docker·容器
lbb 小魔仙8 小时前
【Linux】云原生运维效率提升:Linux 终端工具链(kubectl + tmux + fzf)组合拳教程
linux·运维·云原生
Joren的学习记录9 小时前
【Linux运维大神系列】Kubernetes详解3(kubeadm部署k8s1.23高可用集群)
linux·运维·kubernetes
Hellc0079 小时前
Docker网络冲突排查与解决方案:完整指南
网络·docker·容器
hanyi_qwe9 小时前
发布策略 【K8S (三)】
docker·容器·kubernetes
眠りたいです9 小时前
Docker核心技术和实现原理第二部分:docker镜像与网络原理
运维·网络·docker·容器
Mr. Cao code11 小时前
Docker数据管理:持久化存储最佳实践
java·docker·容器