理解 Kubernetes CRI
关于 CRI,现在的资料已经不少,但我仍希望有一篇文档能让人轻松但不失准确地理解 CRI。
本文不涉及代码分析和详细设计。但需要如下基础:
- 会使用至少一种容器,Docker,containerd,Kata 之类的都可以。
- protobuf 和 gRPC:会用并有少量的开发经验,会用某种语言(最好是 Go)开发简单的 client 和 server。
- k8s:懂得基本概念,会简单使用。
什么是 CRI
CRI 是 kubelet 使用的基于 gRPC API,抽象容器管理和镜像管理,使 Kubernetes 以通过统一的方式与任意容器运行时通信。
形式上,CRI 就是一个 proto 定义文件,再加上以文档形式存在的对 API 的要求。
这意味着,如果我们需要实现一个自定义的 CRI,例如希望用 CRI 管理虚拟机或者做其他一些奇思妙想的事情,只要正确实现 CRI 的 proto 即可。
具体来说:
// Runtime service defines the public APIs for remote container runtimes
service RuntimeService {
//
}
// ImageService defines the public APIs for managing images.
service ImageService {
//
}
CRI 要求实现 2 个 gRPC service。RuntimeService 主要是对容器的操作,包括启动、获取状态之类的,ImageService 包含对镜像的操作,包括列举镜像、拉取镜像之类的。
简单例子
这里给出一个最简单的例子。当用户执行
# 命令 1
kubectl get node -o wide
之后,CONTAINER-RUNTIME 这个字段的值从何而来。
假设集群的各个节点运行着现在最主流的 CRI 运行时 containerd。containerd 启动后默认监听 /run/containerd/containerd.sock 这个 UDS。
而 kubelet 启动时,通过 --container-runtime-endpoint 这个参数让 kubelet 知道本机的 CRI 运行时在监听哪里。此参数的默认值为 "unix:///run/containerd/containerd.sock"。
kubelet 启动后,会调用 RuntimeService.Version 函数获取 CRI 运行时的概况。
当用户执行命令 1 之后,通过 kubectl->kube-apiserver->kubelet 这个链路(不是本文重点,略)告知 kubelet,然后 kubelet 再次调用 RuntimeService.Version 得到如下信息。
message VersionResponse {
// Version of the kubelet runtime API.
string version = 1;
// Name of the container runtime.
string runtime_name = 2;
// Version of the container runtime. The string must be
// semver-compatible.
string runtime_version = 3;
// API version of the container runtime. The string must be
// semver-compatible.
string runtime_api_version = 4;
}
kubelet 在它的代码(Go)中进行拼接:
s := runtimeName + "://" + runtimeVersion
之后返回给调用者。
这里的 s 就是该节点 CONTAINER-RUNTIME 的值。
它的值形如:
containerd://1.7.27 或 docker://28.3.3。

浙公网安备 33010602011771号