引言

这是关于容器运行时系列文章的第四篇,也是最后一篇。 从第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中。
image.png

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之外的低级运行时来运行容器,例如gVisorKata ContainersNabla Containersruntime handler在k8s 1.12 alpha版本的RuntimeClass object中正式被提交,这里有更多关于containerd's shim的概念介绍。

Docker

Docker runtime第一个实现了对CRI的支持,并且作为kubeletDocker之间的一个shim而实现。 从那以后,Docker已将其许多功能分解为容器,现在通过容器支持CRI。 安装最新版本的Docker时,将同时安装containerdCRI直接与containerd通信。 因此,Docker本身并不需要支持CRI。 因此,根据你的实际情况,可以直接安装容器或者通过Docker来安装。

cri-o

cri-o是一个轻量级的CRI运行时,它是Kubernetes特定的高级运行时。 它支持OCI兼容镜像的管理,并从任何OCI兼容镜像注册表中提取。 它支持runcClear Containers作为低级运行时,在理论上支持其他OCI兼容的低级运行时,但依赖于与runc OCI命令行界面的兼容性,因此在实践中它不如容器的shim API灵活。
cri-oendpoints默认情况下位于/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 buffersgRPC API。 该规范是在kubelet下的Kubernetes镜像仓库中的protobuf文件中定义的。 CRI定义了几种远程过程调用(RPCs)和消息类型。 RPCs用于“镜像”(ImageService.PullImage),“创建容器”(RuntimeService.RunPodSandbox),“创建容器”(RuntimeService.CreateContainer),“启动容器”(RuntimeService.StartContainer),“停止容器”等操作 (RuntimeService.StopContainer)等

例如,通过CRI启动一个新的Kubernetes Pod的典型交互看起来类似于以下内容(以我自己的伪gRPC形式,每个RPC都会得到一个更大的请求对象,为简便起见,我对其进行了简化)。 RunPodSandboxCreateContainer 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}
}

EngineerLeo
598 声望38 粉丝

专注于云原生、AI等相关技术