理解 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.27docker://28.3.3

posted @ 2025-07-31 17:13  风华神使  阅读(99)  评论(0)    收藏  举报