在上一期,我们讲到,在kubernetes 1.5版本中,正式引入了CRI接口,使得kubernetes正式进入了兼容异构容器运行时引擎的时代。
CRI接口实际上是基于grpc的。grpc是google remote procedure call(Google远程过程调用)的缩写,由服务器端和客户端组成,如下图所示:
图中,服务器端使用了C 调用grpc的C 库实现,而有两个客户端分别使用ruby语言和java语言实现,当然,也使用了grpc的Ruby和Java语言的库。
grpc提供四类服务方法:
- 单项RPC,客户端发起一次请求,服务器端也进行一次响应,这种服务方法与传统的unix rpc基本相同;
- 服务端流式RPC,客户端发起一次请求(订阅),可以获取服务器端的一系列数据流信息;
- 客户端流式RPC,客户端向服务器端发送数据流,完成后等待服务器端应答;
- 双向流式RPC,客户端和服务器端均发送数据流;
对grpc感兴趣的同学可以在这个地方找到grpc的中文版本详解:
http://doc.oschina.net/grpc?t=58009
在kubernetes中,kubelet是grpc的客户端,而容器运行时引擎(如containerd等),是grpc的服务器端,如下图所示:
CRI的接口实际上也很简单:Kubelet通过gRPC向容器运行时引擎发起请求,容器运行时引擎执行请求并返回响应结果。
它的定义在这里:
https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1alpha2/api.proto
我们只需要从34行RuntimeService的定义看起,可以看出,CRI的接口主要有以下几类:
- 版本请求,只有1个调用:Version
- RuntimeService,对容器或Pod sandbox的运行时管理;
- ImageService,对容器镜像仓库拉取、查看、移除镜像的动作;
那么,目前哪些容器运行时引擎支持基于gRPC的CRI呢?
当然,首先是大名鼎鼎的docker。
敲黑板:docker对CRI的支持有非常特殊的地方,它本来与kubernetes采用的是代码级别紧耦合的方式,在1.5以前的版本的实现中,我们也看到了——在前几章的铺垫中,提到的就是这种紧耦合方式。但由于CRI越来越成为kubernetes调用容器运行时的主流实现方式,docker不得不嘴上说不要,身体很诚实地支持这种实现。
实际上,CRI的主流推动者是CoreOS主推的rkt,它的推出旨在与docker竞争主流容器运行时引擎的地位。如前几篇所提到的,由于CRI能够让kubernetes与容器运行时引擎解耦,大家纷纷支持CRI。
目前支持CRI的容器运行时引擎还有:
cri-o, 来源于redhat的轻量级容器运行时引擎;
containerd, 从docker中剥离出来的容器运行时引擎;
clear-containers, Intel主导的容器运行时引擎;
……
可见,由于CRI的开放性,k8s又添加了一系列生态小伙伴,正所谓得道多助。
反之,如果妄图利用自身优势地位建立霸权,无论是打着什么样的旗号,都只能接受可耻的失败。
70年前如此。
现在也如此。
谨以此小结献给70年前最可爱的人们。
在下一期中,我们详细介绍CRI的三种操作,请大家期待呀!