蛮荆

Kubernetes - CRI 概述

2023-11-07

概述

CRI(Container Runtime Interface, 容器运行时接口)是 Kubernetes 用于管理容器运行时和容器镜像的 gRPC 协议接口集合,kubelet 可以通过 CRI 来使用不同的容器运行时,而无需重新编译集群组件。

为了保证 CRI 可以正常工作,Kubernetes 集群中的每个节点都需要有一个实现了 CRI 的具体容器运行时 (例如 containerd),这样 kubelet 可以直接对 Pod 及其内部容器进行操作。

下面以 containerd 为例进行说明,containerd 是来自 Docker 的高级容器运行时,实现了 CRI 规范

containerd 实现了 CRI

宏观接口模型

因为 Pod 是 Kubernetes 中应用运行的最小单位,此外容器运行时除了运行、重启、停止 Pod 操作外,还有容器对应的镜像拉取、删除等操作, 结合两者,我们可以给出一个粗糙的 CRI 模型示例图:

CRI 模型

然后就可以直接将上述接口模型转化成伪代码 (Go 语言实现):

type CRI interface {
	PullImage(name string)   // 拉取容器镜像
	RemoveImage(name string) // 删除容器镜像

	StartPod(name string)  // 启动 Pod
	StopPod(name string)   // 停止 Pod
	RemovePod(name string) // 删除 Pod

	StartContainer(name string)  // 启动 Pod
	StopContainer(name string)   // 停止 Pod
	RemoveContainer(name string) // 删除 Pod
}

// Containerd (模拟) 实现了 CRI 接口
type Containerd struct {
}

func (c *Containerd) PullImage(name string)       {}
func (c *Containerd) RemoveImage(name string)     {}
func (c *Containerd) StartPod(name string)        {}
...
func (c *Containerd) RemoveContainer(name string) {}

// Rktlet (模拟) 实现了 CRI 接口
type Rktlet struct {
}

func (r *Rktlet) PullImage(name string)       {}
func (r *Rktlet) RemoveImage(name string)     {}
func (r *Rktlet) StartPod(name string)        {}
...
func (d *Rktlet) RemoveContainer(name string) {}

// CRI-O 实现了 CRI 接口
type CRI-O struct {
}

func (c *CRI-O) PullImage(name string)       {}
func (c *CRI-O) RemoveImage(name string)     {}
func (c *CRI-O) StartPod(name string)        {}
...
func (c *CRI-O) RemoveContainer(name string) {}

通过上面的伪代码,我们可以对 CRI 有一个基础的认识,下面我们一起看看 Kubernetes 中 CRI 的代码,学习一下成熟的方案和设计思路。


Kubernetes 中的 CRI

Kubernetes 中的 CRI 功能对应的源代码位于 Kubernetes 项目的 staging/src/k8s.io/cri-api 目录,本文以 Kubernetes v1.28 版本源代码进行分析。

CRI 定义和实现使用的是 gRPC 协议,在对应的 gRPC 定义文件中,可以看到两个 Service:

  1. RuntimeService: 定义了容器运行时的相关操作 API
  2. ImageService: 定义了容器镜像管理的相关操作 API
// cri-api/pkg/apis/runtime/v1/api.proto

service RuntimeService {
    rpc Version(VersionRequest) returns (VersionResponse) {}
	
    rpc RunPodSandbox(RunPodSandboxRequest) returns (RunPodSandboxResponse) {}
    rpc StopPodSandbox(StopPodSandboxRequest) returns (StopPodSandboxResponse) {}
    rpc RemovePodSandbox(RemovePodSandboxRequest) returns (RemovePodSandboxResponse) {}
	
	...
}

service ImageService {
    rpc ListImages(ListImagesRequest) returns (ListImagesResponse) {}
    rpc PullImage(PullImageRequest) returns (PullImageResponse) {}
	
	...
}

上面的 Service 对应的 Go 代码如下:

// cri-api/pkg/apis/services.go

type RuntimeVersioner interface {
	Version(ctx context.Context, apiVersion string) (*runtimeapi.VersionResponse, error)
}

// 容器管理接口
type ContainerManager interface {
	CreateContainer(ctx context.Context, podSandboxID string, ...) (string, error)
	StartContainer(ctx context.Context, containerID string) error
	StopContainer(ctx context.Context, containerID string, timeout int64) error
	RemoveContainer(ctx context.Context, containerID string) error
	ListContainers(ctx context.Context, filter *runtimeapi.ContainerFilter) ([]*runtimeapi.Container, error)
    ...
}

// Pod 管理接口
type PodSandboxManager interface {
	RunPodSandbox(ctx context.Context, ...) (string, error)
	StopPodSandbox(pctx context.Context, odSandboxID string) error
	RemovePodSandbox(ctx context.Context, podSandboxID string) error
    ...
}

// 通过内嵌上述几个接口,形成一个 CRI 主要接口
type RuntimeService interface {
	RuntimeVersioner
	ContainerManager
	PodSandboxManager

	UpdateRuntimeConfig(ctx context.Context, runtimeConfig *runtimeapi.RuntimeConfig) error
	Status(ctx context.Context, verbose bool) (*runtimeapi.StatusResponse, error)
	RuntimeConfig(ctx context.Context) (*runtimeapi.RuntimeConfigResponse, error)
}

// 镜像管理接口
type ImageManagerService interface {
	PullImage(ctx context.Context, image *runtimeapi.ImageSpec, ...) (string, error)
	RemoveImage(ctx context.Context, image *runtimeapi.ImageSpec) error
	...
}

containerd

containerd, Docker 和 CRI 交互

这里以 containerd 为例,看看其内部关于 CRI 接口的具体代码结构,时间所限,这里只留下相关代码骨架截图,具体的源代码不再进行分析。

remote_image.go 实现了容器镜像相关操作

remote_runtime.go 实现了容器运行时相关操作

Reference

扩展阅读

转载申请

本作品采用 知识共享署名 4.0 国际许可协议 进行许可,转载时请注明原文链接,图片在使用时请保留全部内容,商业转载请联系作者获得授权。