引言
这是关于容器运行时系列文章的第四篇,也是最后一篇。 从第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.yaml
runtime-endpoint: unix:///run/containerd/containerd.sock
EOF
这是一个有趣的高级运行时,因为它在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.yaml
runtime-endpoint: unix:///var/run/crio/crio.sock
EOF
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.yaml
runtime-endpoint: unix:///run/containerd/containerd.sock
EOF
或者可以在每次命令行执行时指定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}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。