Kubernetes CRI

文章目录

  • 1 什么是 CRI,为什么 Kubernetes 需要它?
  • 2 CRI 概述
  • 3 Pod 和容器生命周期管理
  • 4 为什么必须要有一个以容器为中心的接口?
  • 5 Exec/attach/port-forward 请求
  • 6 容器运行时实例

在 Kubernetes 最底层负责容器启停的软件,我们称之为“容器运行时”。最广为人知的容器运行时是 Docker,但实际上这个领域百花齐放。为了使 Kubernetes 具备更强的扩展能力,我们为容器运行时搞出了新的插件 API,叫做 CRI。

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

每种容器运行时都有它的特点,很多用户希望 Kubernetes 支持更多的运行时。在 Kubernetes 1.5 发布之际,我们很自豪引入了容器运行时接口——这是一种能让 kubelet 无需重新编译就可以广泛使用各种容器运行时的插件接口。CRI y由 protocol buffers 和 gRPC API 还有 streaming 库构成,正在火热开发中。CRI 在 Kubernetes 1.5 中发布 Alpha 版。

支持更换容器运行时在 Kubernetes 中已经不是什么新概念了。在 1.3 发布时,我们宣布 rktnetes 项目来将 rkt 容器运行时作为 Docker 容器运行时以外的选项。但是 Docker 与 rkt 深度整合在了 kubelet 源码中,这种集成需要深度理解 Kubernetes 内部,并给 Kubernetes 社区带造成了大量的维护开销,这些因素对新的容器运行时形成了高墙。通过提供明确定义的抽象层,我们清除了障碍并使开发人员专注于构建他们自己的容器运行时。这是朝着真正实现可插拔的容器运行时和构建更健康的生态系统迈出的一小步,但却很重要。

CRI 概述

kubelet 和容器运行时(或者是运行时的 CRI shim)通过 Unix 套接字走 gRPC 通讯。

protocol buffers API 包括两种 gRPC 服务,镜像服务(ImageService)和运行时服务(RuntimeService)。镜像服务提供了从镜像仓库拉取镜像、检查、删除镜像的接口;运行时服务提供了管理容器和 Pod 生命周期以及与容器交互(exec/attach/port-forward)的接口。一个同时管理镜像和容器的单运行时(例如 Docker 和 rkt)可以用一个套接字同时提供这两种服务。可以通过 --container-runtime-endpoint 和 --image-service-endpoint 参数在 kubelet 中设置此套接字,默认是 unix:///var/run/dockershim.sock 即默认使用本地的 Docker 作为容器运行时。

Pod 和容器生命周期管理

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 中,这个环境被称为 Pod 沙盒。我们有意为容器运行时预留一些空间,让它们根据内部操作方式对 Pod 沙盒进行不同的实现。对于基于 hypervisor 的运行时,Pod 沙盒可能代表虚拟机;对于其他的,比如 Docker,它又可能是 Linux 命名空间。Pod 沙盒必须遵循 Pod 资源规范,在 v1alpha1 版 API 中,这是通过在 由 kubelet 创建并传递给运行时的 pod 级 cgroup 内的启动所有进程来实现的。

在启动 Pod 前,kubelet 调用 RuntimeService.RunPodSandbox 来创建环境。这包括了为 Pod 设置网络(分配 IP)。当 Pod 沙盒激活,单个容器可以独立地创建/启动/停止/删除。要删掉 Pod,kubelet 会先停止并删除容器。

kubelet 负责通过 RPC 接口管理容器生命周期,执行容器生命周期钩子函数和 liveness/readiness 检查,同时遵循 Pod 的重启策略。

为什么必须要有一个以容器为中心的接口?

Kubernetes 使用声明式 API 来描述 Pod 资源。我们考虑过的一种可能的设计是 CRI 在其抽象中重用声明的 Pod 对象,让容器运行时自由地实现自己的控制逻辑来达到期望的状态。这将极大地简化 API 并使得 CRI 能够与更多的运行时协作。我们在设计初期就讨论了这种方法,出于几个原因决定不采用它。首先有许多 Pod 级的特性与特定的机制(崩溃回退逻辑),重新实现对所有运行时来说都是很大的负担。其次更重要的是,Pod 规范仍在高速发展中。诸多新功能(init container)不需要动底层运行时,只要 kubelet 直接管理容器。CRI 采用了必要的容器级接口,这样运行时可以共享这些功能已加快开发速度。这不代表我们偏离了“级别触发”的理念——kubelet 负责确保实际状态趋近声明的状态。

Exec/attach/port-forward 请求

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 通过调用容器运行时的本地方法或者使用主机上的工具(nsenter 和 socat)来支持这些功能。使用主机上的工具并不是一个好的解决方案因为大多数工具都基于 Linux 命名空间。在 CRI 中,我们明确在 API 中定义了这些调用来允许运行时自行实现。

另一个潜在的问题是所有容器的流式请求都经过 kubelet 有可能会成为节点上网络流量的瓶颈。在设计 CRI 时,我们听取了这个反馈使运行时消除中间人。容器运行时可以根据请求启动一个单独的流式服务器并将地址返回给 kubelet,kubelet 然后将这个信息再返回给 Kubernetes 的 apiserver,它会打开直接与运行时提供的服务器相连的流连接,并通过它跟客户端连通。

容器运行时实例

CRI 维护者 主要特性 容器引擎
dockershim Kubernetes 内置实现、特性最新 Docker
cri-o cri-o OCI 标准不需要 Docker OCI(runc、kata、gVisor…)
cri-containerd Containerd 基于 containerd 不需要 Docker OCI(runc、kata、gVisor…)
frakti Kubernetes 虚拟化容器 hyperd、Docker
rktlet Kubernetes 支持 rkt rkt
PouchContainer Alibaba 富容器 OCI(runc、kata…)
Virtlet Mirantis 虚拟机和 qcow2 镜像 libvirt(kvm)

CRI 还有很多其他方面的内容没有在本文中提及。请参阅设计文档和提案,了解所有细节。

(0)

相关推荐

  • Docker 兴衰记:关于开源的一些思考

    Docker support in the kubelet is now deprecated and will be removed in a future release. The kubelet ...

  • 致运维:关于 Kubernetes 的架构,看完这篇你就明白了

    打开这篇文章的同学,想必对 docker 都不会陌生.docker 是一种虚拟容器技术,它上手比较简单,只需在宿主机上起一个 docker engine,然后就能愉快的玩耍了,如:拉镜像.起容器.挂载 ...

  • Kubernetes和Docker的关系是什么?

    作为一名容器时代的程序员相信你已经或多或少接触过Docker,但同时你也会发现Docker虽然流行了多年,但之前却很少有公司直接将线上应用通过Docker容器进行大规模地部署.但最近三年,你会发现几乎 ...

  • 是时候跟Docker说再见了

    在容器的远古时代 (差不多就是 4 年前),Docker 是这场游戏的唯一玩家.但现在情况已经不一样了,Docker 不再是唯一玩家,而只是一个容器引擎而已.我们可以用 Docker 构建.运行.拉取 ...

  • kubernetes1.20用containerd替换docker(shim)

    kubernetes 1.20 要去掉对 Docker的支持,具体看这里,本篇文章介绍用 containerd 替换 docker,从work节点开始,然后才到master节点. 首先查看集群 [ro ...

  • kubernetes CRI 前世今生

    在学习kubernetes的过程中,我们会遇到CRI.CNI.CSI.OCI 等术语,本文试图先通过分析k8s目前默认的一种容器运行时架构,来帮助我们更好理解k8s 运行时背后设计逻辑.进而引出CRI ...

  • (49条消息) 在Kubernetes中使用CRI

    在容器实践线路图中介绍了容器技术选型,关于容器运行时,提到了CRI规范与CRI-O实现,使用CRI-O可以在运行时完全替代docker.CRI-O提供了crictl工具,类似docker client ...

  • Kubernetes(k8s)容器运行时(CRI)简介

    Kubernetes节点的底层由一个叫做"容器运行时"的软件进行支撑,它负责比如启停容器这样的事情.最广为人知的容器运行时当属Docker,但它不是唯一的.事实上,容器运行时这个领 ...

  • 我到底应该使用哪个 CRI 替换 kubernetes 集群的 Docker?

    前一段时间 kubernetes 对 docker 的弃用引起了不小的讨论,但其实 docker 并不是 kubernetes 中的 CRI 唯一实现.那么除了 docker 之外,我们还可以使用其他 ...

  • 使用Kubernetes,一个人如何支撑起创业公司运作?

    转载:机器之心 一篇来自创业公司的技术分享,主要介绍了在 AWS 上使用 Kubernetes,从负载平衡到 cron 作业监控,再到支付和订阅. Kubernetes 是一款开源软件,你可以利用它大 ...

  • 生产环境中的Kubernetes最佳实践

    DevOps从提出到现在,已经走过了一段很长的路.包括Docker和Kubernetes在内的多种平台也已经帮助企业用前所未有的速度实现了软件应用的交付.同时,随着应用的容器化构建和发布比率不断上升, ...

  • 面向初学者的Kubernetes基础知识:体系结构和组件

    学习Kubernetes架构和组件 8分钟阅读 来源: 迫切需要使我们的复杂应用程序具有高可用性,可扩展性,可移植性以及可在小模块中独立部署,这导致了Kubernetes的诞生. 今天我们将介绍: 什 ...

  • Kubernetes官方java客户端之八:fluent style

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  • Kubernetes官方java客户端之七:patch操作

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...