引言
这是对于容器运行时系列文章的第四篇,也是最初一篇。 从第1篇开始曾经有一段时间了,在那篇文章中,我概述了容器运行时,并探讨了低级和高级运行时之间的区别。 在第2篇文章中,我具体介绍了低级容器运行时,并构建了一个简略的低级运行时。 在第3篇文章中,我降级了技术栈,介绍了高级容器运行时。
Kubernetes运行时反对容器运行时接口(CRI)的高级容器运行时。 CRI在Kubernetes 1.5中引入,并充当kubelet和容器运行时之间的桥梁,冀望与Kubernetes集成的高级容器运行时实现CRI。 预计运行时将解决镜像治理并反对Kubernetes Pod,并治理各个容器,因而依据咱们在第3篇文章中的定义,Kubernetes运行时必须是高级运行时。低级运行时短少一些必要的个性。 因为第3篇文章介绍了无关高级容器运行时的所有内容,因而在本文中,我将重点介绍CRI,并介绍一些反对CRI的运行时。
为了更多地理解CRI,值得看一下Kubernetes架构。 Kubelet是一个位于Kubernetes集群中每个工作节点上的代理。 Kubelet负责管理其节点的容器工作负载,当波及到理论运行工作负载时,kubelet应用CRI与在同一节点上运行的容器运行时进行通信。 这样,CRI仅仅是一个形象层或API,它使您能够将容器运行时的实现独自拆分进去,而不用将其内置到kubelet中。
CRI运行时示例
这里列出一些可与Kubernetes一起应用的CRI运行时。
containerd
containerd是我在第3篇文章中提到的高级运行时。containerd可能是以后最风行的CRI运行时,它将CRI实现作为默认状况下启用的插件。 默认状况下,它在unix socket上开启监听,因而通过如下配置连贯到容器:
cat <<EOF | sudo tee /etc/crictl.yamlruntime-endpoint: unix:///run/containerd/containerd.sockEOF
这是一个乏味的高级运行时,因为它在1.2版开始通过称为“runtime handler
”的货色反对多个低级运行时。 runtime handler
是通过CRI
中的一个字段传递的,基于该运行时处理程序的容器将运行一个名为shim
的应用程序以启动容器。 它能够用于应用除runc
之外的低级运行时来运行容器,例如gVisor
,Kata Containers
或Nabla Containers
。 runtime handler
在k8s 1.12 alpha版本的RuntimeClass object
中正式被提交,这里有更多对于containerd's shim
的概念介绍。
Docker
Docker runtime
第一个实现了对CRI
的反对,并且作为kubelet
和Docker
之间的一个shim
而实现。 从那以后,Docker
已将其许多性能合成为容器,当初通过容器反对CRI
。 装置最新版本的Docker
时,将同时装置containerd
和CRI
间接与containerd
通信。 因而,Docker
自身并不需要反对CRI
。 因而,依据你的理论状况,能够间接装置容器或者通过Docker
来装置。
cri-o
cri-o
是一个轻量级的CRI
运行时,它是Kubernetes
特定的高级运行时。 它反对OCI
兼容镜像的治理,并从任何OCI
兼容镜像注册表中提取。 它反对runc
和Clear Containers
作为低级运行时,在实践上反对其余OCI兼容的低级运行时,但依赖于与runc OCI
命令行界面的兼容性,因而在实践中它不如容器的shim API
灵便。cri-o
的endpoints
默认状况下位于/var/run/crio/crio.sock
,因而能够通过如下形式配置crictl
:
cat <<EOF | sudo tee /etc/crictl.yamlruntime-endpoint: unix:///var/run/crio/crio.sockEOF
CRI标准
CRI
是一个protocol buffers
和gRPC API
。 该标准是在kubelet
下的Kubernetes
镜像仓库中的protobuf
文件中定义的。 CRI
定义了几种近程过程调用(RPCs
)和音讯类型。 RPCs
用于“镜像”(ImageService.PullImage
),“创立容器”(RuntimeService.RunPodSandbox
),“创立容器”(RuntimeService.CreateContainer
),“启动容器”(RuntimeService.StartContainer
),“进行容器”等操作 (RuntimeService.StopContainer
)等
例如,通过CRI
启动一个新的Kubernetes Pod的典型交互看起来相似于以下内容(以我本人的伪gRPC
模式,每个RPC
都会失去一个更大的申请对象,为简便起见,我对其进行了简化)。 RunPodSandbox
和CreateContainer RPC
在其响应中返回ID,这些ID在后续申请中应用:
ImageService.PullImage({image: "image1"})ImageService.PullImage({image: "image2"})podID = RuntimeService.RunPodSandbox({name: "mypod"})id1 = RuntimeService.CreateContainer({ pod: podID, name: "container1", image: "image1",})id2 = RuntimeService.CreateContainer({ pod: podID, name: "container2", image: "image2",})RuntimeService.StartContainer({id: id1})RuntimeService.StartContainer({id: id2})
应用crictl
工具能够间接与CRI
运行时进行交互,能够间接从命令即将gRPC消
息发送到CRI
运行时并用它来调试和测试CRI
实现,而无需启动kubelet
或Kubernetes集群,能够从GitHub上cri-tools版本页面下载crictl二进制文件
来获取相干文件。
能够通过在/etc/crictl.yaml
下创立配置文件来配置crictl
。 在这里,你应该将运行时的gRPC
端点指定为Unix socket
文件(unix:///path/to/file
)或TCP端点(tcp://<host>:<port>
)。 在本例中将应用containerd
:
cat <<EOF | sudo tee /etc/crictl.yamlruntime-endpoint: unix:///run/containerd/containerd.sockEOF
或者能够在每次命令行执行时指定runtime endpoint
:
crictl --runtime-endpoint unix:///run/containerd/containerd.sock …
应用crictl
运行一个单容器pod
, 首先,通知运行时pull
所需的nginx
镜像,因为没有本地存储的镜像就无奈启动容器。
sudo crictl pull nginx
接下来创立一个Pod
的创立申请,能够应用JSON
文件进行操作。
cat <<EOF | tee sandbox.json{ "metadata": { "name": "nginx-sandbox", "namespace": "default", "attempt": 1, "uid": "hdishd83djaidwnduwk28bcsb" }, "linux": { }, "log_directory": "/tmp"}EOF
而后创立pod sandbox
,将sandbox
的ID存储为SANDBOX_ID
。
SANDBOX_ID=$(sudo crictl runp --runtime runsc sandbox.json)
接下来,在JSON
文件中创立容器的创立申请。
cat <<EOF | tee container.json{ "metadata": { "name": "nginx" }, "image":{ "image": "nginx" }, "log_path":"nginx.0.log", "linux": { }}EOF
而后,在后面创立的Pod
中创立并启动容器。
{ CONTAINER_ID=$(sudo crictl create ${SANDBOX_ID} container.json sandbox.json) sudo crictl start ${CONTAINER_ID}}
查看正在运行的pod
以及正在运行的容器:
sudo crictl inspectp ${SANDBOX_ID}sudo crictl inspect ${CONTAINER_ID}
通过进行并删除容器进行清理:
{ sudo crictl stop ${CONTAINER_ID} sudo crictl rm ${CONTAINER_ID}}
而后进行并删除Pod
:
{ sudo crictl stopp ${SANDBOX_ID} sudo crictl rmp ${SANDBOX_ID}}