Kubernetes节点的底层由一个叫做“容器运行时”的软件进行支撑,它负责比如启停容器这样的事情。最广为人知的容器运行时当属Docker,但它不是唯一的。事实上,容器运行时这个领域发展迅速。为了使Kubernetes的扩展变得更容易,我们一直在打磨支持容器运行时的K8s插件API:容器运行时接口(Container Runtime Interface, CRI)。

CRI是什么?

每种容器运行时各有所长,许多用户都希望Kubernetes支持更多的运行时。在Kubernetes 1.5发布版里,我们引入了CRI–一个能让kubelet无需编译就可以支持多种容器运行时的插件接口。CRI包含了一组protocol buffers,gRPC API,相关的库,以及在活跃开发下的额外规范和工具。CRI目前是Alpha版本。

支持可替换的容器运行时在Kubernetes中概念中并非首次。在1.3发布版里,我们介绍了rktnetes项目,它可以让rkt容器引擎作为Docker容器运行时的一个备选。然而,不管是Docker还是Rkt都需要通过内部、不太稳定的接口直接集成到kubelet的源码中。这样的集成过程要求十分熟悉kubelet内部原理,并且还会在Kubernetes社区引发巨大的维护反响。这些因素都在为容器运行时的初期造成了巨大的困难。我们通过提供一个清晰定义的抽象层消除了这些障碍,开发者可以专注于构建他们的容器运行时。这是很小的一步,但对于真正提供可插拔的容器运行时和构建一个更健康的生态系统却意义非凡。

CRI总览

Kubelet与容器运行时通信(或者是CRI插件填充了容器运行时)时,Kubelet就像是客户端,而CRI插件就像对应的服务器。它们之间可以通过Unix 套接字或者gRPC框架进行通信。

protocol buffers API包含了两个gRPC服务:ImageService和RuntimeService。ImageService提供了从镜像仓库拉取、查看、和移除镜像的RPC。RuntimeSerivce包含了Pods和容器生命周期管理的RPC,以及跟容器交互的调用(exec/attach/port-forward)。一个单块的容器运行时能够管理镜像和容器(例如:Docker和Rkt),并且通过同一个套接字同时提供这两种服务。这个套接字可以在Kubelet里通过标识–container-runtime-endpoint和–image-service-endpoint进行设置。

生命周期管理

对于Pod和容器的生命周期管理,CRI提供了下面的机制:

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。对于基于hypervisor的运行时,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级的特性和特定的技术(比如crash-loop backoff逻辑),这会成为所有运行时重新实现时的巨大负担。其次,越来越重要的是,Pod的定义更新快速。只要kubelet直接管理容器,那么许多新特性(比如init container)不需要底层容器运行时做任何改变。CRI包含了一个必要的容器级接口,这样运行时就可以共享这些特性,拥有更快的开发速度。当然这并不意味着我们偏离了”level triggered”哲学。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 PodSandbox.
rpc PortForward(PortForwardRequest) returns (PortForwardResponse) {}

}

Kubernetes提供了一些用户可以与Pod及其内部容器进行交互的特性(例如kubectl exec/attach/port-forward)。Kubelet现在通过调用容器原生的方法或使用节点上可用的工具(例如nsenter和socat)来支持这些特性。在节点上使用这些工具不是一个可移植的好办法,因为这些工具的大部分假定Pod是通过Linux命名空间进行隔离的。在CRI,我们显式定义了这些调用,允许特定的运行时实现。

另外一个潜在的问题是,kubelet如今的实现是kubelet处理所有的流式连接请求。所以这会给节点的网络流量带来瓶颈。在设计CRI的时候,我们采纳了这个反馈,支持运行时防范中间人。容器运行时可以启动一个对应请求的单独的流服务器(甚至可能为Pod审计资源使用),并且将地址返回给Kubelet。Kubelet然后将这个信息再返回给Kubernetes API Server,它会打开直接与运行时提供的服务器相连的流连接,并将它跟客户端连通。

这篇博文并没有包含CRI的全部。更多细节请参考设计文档和建议。

当前状态

尽管CRI还处于早期阶段,已经有不少使用CRI来集成容器运行时的项目在开发中。下面是一些列子:

  • cri-o: OCI运行时
  • rktlt: rkt容器运行时
  • frakti: 基于hypervisor的容器运行时
  • docker CRI shim

如果你对上面列出的这些运行时感兴趣,你可以关注这些独立的github仓库,获取最新的进展和说明。

对集成新的容器运行时感兴趣的开发者,请参考开发指南了解这些API的限制和问题。我们会从早期的开发者那里积极采纳反馈来提升API。开发者可能会遇到API的一些意外改动(毕竟是Alpha版)。

集成CRI-Docker

Kubelet至今还没有默认使用CRI,但我们仍在积极地推动。第一步就是使用CRI将Docker重新集成到kubelet里。在1.5发布版里,我们扩展了Kubelet来支持CRI,并且为Docker添加了内置的CRI插件。kubelet启动一个gRPC服务器,代表Docker。如果尝试新的kubelet-CRI-Docker集成,你可能仅仅会使用–feature-gates=StreamingProxyRedirects=true来打开Kubernetes API Server,以启动新的流重定向特性,并且通过设置kubelet的标识–experimental-cri=true来启动。

除了一些欠缺的特性,新的集成可以一直通过主要的端到端测试。我们计划尽快扩展测试的覆盖率,并且鼓励社区反应关于这个转化的任何问题。

Minikube与CRI

如果你想要尝试新的集成,但是没有时间在云上启动一个新的测试集群。minikube是一个很棒的工具,你可以迅速在本地搭建集群。在你开始前,请阅读说明并下载安装Minikube:

1.检查可用的Kubernetes版本,选择可用的最新1.5.x版本。我们使用v1.5.0-beta.1作为示例。

$ minikube get-k8s-versions

2.通过内建的Docker CRI集成启动一个Minikube集群。 –extra-config=kubelet.EnableCRI=true开启了kubelet的CRI实现。–network-plugin=kubenet和–extra-

config=kubelet.PodCIDR=10.180.1.0/24设置Kubenet网络插件,保证分配给节点的PodCIDR。–iso-url设置本地节点启动的minikube iso镜像。

$ 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

3.检查minikube日志,查看启动CRI

$ minikube logs | grep EnableCRI
I1209 01:48:51.150789 3226 localkube.go:116] Setting EnableCRI to true on kubelet.

4.创建pod,检查它的状态。你应该可以看见一个”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 minikube
...{kubelet minikube} Normal SandboxReceived Pod sandbox received, it will be created.

注意:kubectl attach/exec/port-forward还不能在minikube的CRI中运行。但这会在新版本的minikube中得到改善。

社区

CRI的开发很活跃,由Kubernetes SIG-Node兴趣小组维护。我们热切地期盼你的回复。加入社区吧:

  • 通过Github反馈问题和特性请求
  • 加入Slack上的#sig-node频道
  • 参与SIG-Node邮件列表
  • 关注我们Twitter @Kubernetesio的后续更新

CRI-O将如何把Kubernetes推上容器生态系统的中心位置

https://www.kubernetes.org.cn/572.html

本文由立尧翻译,由kuberneters中文社区授权转载。

Kubernetes容器运行时(CRI)简介的更多相关文章

  1. Kubernetes容器运行时弃用Docker转型Containerd

    文章转载自:https://i4t.com/5435.html Kubernetes社区在2020年7月份发布的版本中已经开始了dockershim的移除计划,在1.20版本中将内置的dockersh ...

  2. CRI 与 ShimV2:一种 Kubernetes 集成容器运行时的新思路

    摘要: 关于 Kubernetes 接口化设计.CRI.容器运行时.shimv2.RuntimeClass 等关键技术特性的设计与实现.     Kubernetes 项目目前的重点发展方向,是为开发 ...

  3. kubernetes/k8s CRI分析-容器运行时接口分析

    关联博客:kubernetes/k8s CSI分析-容器存储接口分析 概述 kubernetes的设计初衷是支持可插拔架构,从而利于扩展kubernetes的功能.在此架构思想下,kubernetes ...

  4. 第28 章 : 理解容器运行时接口 CRI

    理解容器运行时接口 CRI CRI 是 Kubernetes 体系中跟容器打交道的一个非常重要的部分.本文将主要分享以下三方面的内容: CRI 介绍 CRI 实现 相关工具 CRI 介绍 在 CRI ...

  5. 使用kubeoperator安装的k8s 版本1.20.14 将节点上的容器运行时从 Docker Engine 改为 containerd

    官方文档:https://kubernetes.io/zh-cn/docs/tasks/administer-cluster/migrating-from-dockershim/change-runt ...

  6. kubernetes容器删除时快速释放ip的方案

    问题的来由 在kubernetes集群的生产中,经常遇到这样的一个问题,就是在应用大规模更新时,大量容器删除而后大量容器创建,创建的容器需要很长时间才能就绪.这其中一个可能的原因,就是大量容器删除释放 ...

  7. Kubernetes(k8s)容器运行时(CRI)

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

  8. Kubernetes容器调度

    Kubernetes的调度器是Kubernetes众多组件的一部分,独立于API服务器之外.调度器本身是可插拔的,任何理解调度器和API服务器之间调用关系的工程师都可以编写定制的调度器.本文后面的介绍 ...

  9. kubernetes容器编排之定义环境变量以及通过downwardapi把pod信息作为环境变量传入容器内

    系列目录 在学习docker的时候,大家可能经常看到不少示例在docker run的时候指定环境变量(比如wordpress的docker示例就是通过环境变量传入账户和密码到容器内).这里之所以经常用 ...

随机推荐

  1. Linux上安装pip以及setuptools

    毕竟丰富的第三方库是python的优势所在,为了更加方便的安装第三方库,使用pip命令,我们需要进行相应的安装. 1.安装pip前需要前置安装setuptools 命令如下: wget --no-ch ...

  2. HBase存储架构

    以下的介绍是基于Apache Hbase 0.94版本: 从HBase的架构图上可以看出,HBase中的存储包括HMaster.HRegionServer.HRegion.Store.MemStore ...

  3. request.getInputStream() 流只能读取一次问题

    问题: 一次开发过程中同事在 sptring interceptor 中获取 request body 中值,以对数据的校验和预处理等操作 .导致之后spring 在读取request body 值做 ...

  4. linux内核源代码、配置与编译

    内核源代码下载:www.kernel.org Linux内核源代码采用树形结构进行组织,非常合理地把功能相关的文件都放在同一个子目录下,使得程序更具可读性. linux内核代码最好不要在windows ...

  5. Ubuntu安装samba实现文件夹共享

    因工作需要,准备在Ubuntu服务器上共享文件夹,从Windows和Mac上都可以访问共享文件. 搜了一下,决定通过samba服务实现.安装过程如下: [step1]安装samba服务 sudo ap ...

  6. 如何配置IIS服务器?

    1, 先安装IIS 然后安装vs; 注: 顺序颠倒则执行cmd命令: 1,cd \ 2,cd Windows 3, cd  Microsoft.NET 4, dir 5,cd Framework 6, ...

  7. Spark高级数据分析· 2数据分析

    wget https://archive.ics.uci.edu/ml/machine-learning-databases/00210/donation.zip 数据清洗 cd /Users/eri ...

  8. 20145328 《Java程序设计》第2周学习总结

    20145328 <Java程序设计>第2周学习总结 教材学习内容总结 掌握了上周没有学会的IDEA的用法 掌握了一些快捷键用法,在用IDEA编写程序的过程中的体验比直接使用cmd进行编写 ...

  9. 20145329 吉东云《Java程序设计》第二周学习总结

    教材学习内容总结 第三章 基础语法 基本类型 1.整数(short.int.long) 2.字节(byte),可表示-128~127的整数 3.浮点数(float/double),主要储存小数数值 4 ...

  10. redis命令的使用

    批量删除特定前缀的keys redis-cli KEYS "prefix:*" | xargs redis-cli DEL 返回list的长度 > LPUSH test &q ...