首页 > 编程语言 >containerd 源码分析:kubelet 和 containerd 交互

containerd 源码分析:kubelet 和 containerd 交互

时间:2024-05-22 17:41:35浏览次数:18  
标签:... runtime nil err containerd kubelet 源码 cri


0. 前言

Kubernetes:kubelet 源码分析之创建 pod 流程 介绍了 kubelet 创建 pod 的流程,其中介绍了 kubelet 调用 runtime cri 接口创建 pod。containerd 源码分析:启动注册流程 介绍了 containerd 作为一种行业标准的高级运行时的启动注册流程。那么,kubelet 是怎么和 containerd 交互的呢? 本文会带着这个问题分析 kubeletcontainerd 的交互。

1. kubelet 和 containerd 交互

1.1 kubelet

Kubernetes:kubelet 源码分析之创建 pod 流程 分析,kubelet 调用 runtime cri 接口 /runtime.v1.RuntimeService/RunPodSandbox 创建 pod:

// kubernetes/vendor/k8s.io/cri-api/pkg/apis/runtime/v1/api.pb.go
func (c *runtimeServiceClient) RunPodSandbox(ctx context.Context, in *RunPodSandboxRequest, opts ...grpc.CallOption) (*RunPodSandboxResponse, error) {
	out := new(RunPodSandboxResponse)
	err := c.cc.Invoke(ctx, "/runtime.v1.RuntimeService/RunPodSandbox", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

kubelet 是 runtime cri 接口调用的客户端,那么容器运行时作为服务端是怎么提供服务的呢?

1.2 kubelet 和 containerd 交互流程

在介绍容器运行时提供的服务之前先看下 cri 架构图

image

从图中可以看出,containerd 的 CRI 插件提供 image serviceruntime service,负责对接 kubelet runtime cri 的接口调用,并将调用转发给 containerd

继续,查看 containerd 的处理流程。

1.3 containerd

1.3.1 CRI Plugin

根据 cri 架构图, 从 CRI 插件入手查看 id 为 io.containerd.grpc.v1.criCRI 插件。

// containerd/plugins/cri/cri.go
func initCRIService(ic *plugin.InitContext) (interface{}, error) {
	...
    // Get runtime service.
	criRuntimePlugin, err := ic.GetByID(plugins.CRIServicePlugin, "runtime")
	if err != nil {
		return nil, fmt.Errorf("unable to load CRI runtime service plugin dependency: %w", err)
	}

    // Get image service.
	criImagePlugin, err := ic.GetByID(plugins.CRIServicePlugin, "images")
	if err != nil {
		return nil, fmt.Errorf("unable to load CRI image service plugin dependency: %w", err)
	}
    ...
    service := &criGRPCServer{
		RuntimeServiceServer: rs,
		ImageServiceServer:   is,
		Closer:               s, // TODO: Where is close run?
		initializer:          s,
	}

	if config.DisableTCPService {
		return service, nil
	}

	return criGRPCServerWithTCP{service}, nil
}

插件返回的是 criGRPCServerWithTCP 对象。其中,包括 criGRPCServer 对象。criGRPCServer 对象实现了 grpcService 接口,将调用接口的 Register 注册对象到 grpc server。

// containerd/plugins/cri/cri.go
// Register registers all required services onto a specific grpc server.
// This is used by containerd cri plugin.
func (c *criGRPCServer) Register(s *grpc.Server) error {
	return c.register(s)
}

func (c *criGRPCServer) register(s *grpc.Server) error {
	instrumented := instrument.NewService(c)
	runtime.RegisterRuntimeServiceServer(s, instrumented)
	runtime.RegisterImageServiceServer(s, instrumented)
	return nil
}

criGRPCServer.register 中创建 instrumentedService 对象。

type instrumentedService struct {
	c criService
}

func NewService(c criService) GRPCServices {
	return &instrumentedService{c: c}
}

instrumentedService 包括 criService 对象。实际提供 runtime serviceimage service 的就是 criService 对象。

以注册 runtime service 为例,查看 runtime.RegisterRuntimeServiceServer(s, instrumented) 做了什么。

// containerd/vendor/k8s.io/cri-api/pkg/apis/runtime/v1/api.pb.go
func RegisterRuntimeServiceServer(s *grpc.Server, srv RuntimeServiceServer) {
	s.RegisterService(&_RuntimeService_serviceDesc, srv)
}

var _RuntimeService_serviceDesc = grpc.ServiceDesc{
	ServiceName: "runtime.v1.RuntimeService",
	HandlerType: (*RuntimeServiceServer)(nil),
	Methods: []grpc.MethodDesc{
		{
			MethodName: "Version",
			Handler:    _RuntimeService_Version_Handler,
		},
		{
			MethodName: "RunPodSandbox",
			Handler:    _RuntimeService_RunPodSandbox_Handler,
		},
        ...
    },
    ...
}

可以看到,注册 instrumentedService 到 grpc 中,instrumentedService 提供 runtime.v1.RuntimeService 服务,包括 kubelet 调用的 RunPodSandbox 方法。

继续看,instrumentedServiceRunPodSandbox 做了什么。

// containerd/internal/cri/instrumented_service.go
func (in *instrumentedService) RunPodSandbox(ctx context.Context, r *runtime.RunPodSandboxRequest) (res *runtime.RunPodSandboxResponse, err error) {
	...
	res, err = in.c.RunPodSandbox(ctrdutil.WithNamespace(ctx), r)
	return res, errdefs.ToGRPC(err)
}

instrumentedService 调用 criGRPCServerRunPodSandbox 方法,实际执行的是 criGRPCServer 中的 criServer 对象:

// containerd/internal/cri/server/sandbox_run.go
func (c *criService) RunPodSandbox(ctx context.Context, r *runtime.RunPodSandboxRequest) (_ *runtime.RunPodSandboxResponse, retErr error) {
	...
    if err := c.sandboxService.CreateSandbox(ctx, sandboxInfo, sb.WithOptions(config), sb.WithNetNSPath(sandbox.NetNSPath)); err != nil {
		return nil, fmt.Errorf("failed to create sandbox %q: %w", id, err)
	}

	ctrl, err := c.sandboxService.StartSandbox(ctx, sandbox.Sandboxer, id)
    if err != nil {
        ...
    }
    ...
}

criService.RunPodSandbox 调用的是 sandboxServiceCreateSandboxStartSandbox 方法。

1.3.2 sanbox Plugin

sandboxServicecri.initCRIService 中实例化:

// containerd/plugins/cri/cri.go
func initCRIService(ic *plugin.InitContext) (interface{}, error) {
    ...
    sbControllers, err := getSandboxControllers(ic)
	if err != nil {
		return nil, fmt.Errorf("failed to get sandbox controllers from plugins %v", err)
	}
    ...
    options := &server.CRIServiceOptions{
		RuntimeService:     criRuntimePlugin.(server.RuntimeService),
		ImageService:       criImagePlugin.(server.ImageService),
		StreamingConfig:    streamingConfig,
		NRI:                getNRIAPI(ic),
		Client:             client,
		SandboxControllers: sbControllers,
	}
    ...
    s, rs, err := server.NewCRIService(options)
    ...
    service := &criGRPCServer{
		RuntimeServiceServer: rs,
		ImageServiceServer:   is,
		Closer:               s, // TODO: Where is close run?
		initializer:          s,
	}
}

首先,getSandboxControllers 获得 sandbox controllers:

// containerd/plugins/cri/cri.go
func getSandboxControllers(ic *plugin.InitContext) (map[string]sandbox.Controller, error) {
    // plugins.SandboxControllerPlugin: "io.containerd.sandbox.controller.v1"
	sandboxers, err := ic.GetByType(plugins.SandboxControllerPlugin)
	if err != nil {
		return nil, err
	}
	...
	return sc, nil
}

sandbox.Controller 是类型为 io.containerd.sandbox.controller.v1 的插件对象。将该对象作为 options 赋给 criServer

// containerd/internal/cri/server/service.go
func NewCRIService(options *CRIServiceOptions) (CRIService, runtime.RuntimeServiceServer, error) {
	...
	c := &criService{
		...
		sandboxService:     newCriSandboxService(&config, options.SandboxControllers),
	}
    ...
}

func newCriSandboxService(config *criconfig.Config, sandboxers map[string]sandbox.Controller) *criSandboxService {
	return &criSandboxService{
		sandboxControllers: sandboxers,
		config:             config,
	}
}

criService.sandboxService.CreateSandbox 调用的是插件对象 sanbox controllersCreateSandbox 方法,该方法最终调用的是 sandboxClientCreateSandbox

func (c *sandboxClient) CreateSandbox(ctx context.Context, in *CreateSandboxRequest, opts ...grpc.CallOption) (*CreateSandboxResponse, error) {
	out := new(CreateSandboxResponse)
	err := c.cc.Invoke(ctx, "/containerd.runtime.sandbox.v1.Sandbox/CreateSandbox", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

可以看到,在 sandboxClient.CreateSandbox 中调用 containerd 提供的 containerd cri 接口 /containerd.runtime.sandbox.v1.Sandbox/CreateSandbox,该接口用来创建 sandbox,即 pod。

1.4 创建 pod 流程

根据上述分析,这里画出 kubeletcontainerd 的交互流程图如下:
image

2. 小结

本文在前文 Kubernetes:kubelet 源码分析之创建 pod 流程containerd 源码分析:启动注册流程 的基础上,进一步分析从 kubeletcontainerd 的交互流程,打通了 kubeletcontainerd 这一步。


标签:...,runtime,nil,err,containerd,kubelet,源码,cri
From: https://www.cnblogs.com/xingzheanan/p/18206781

相关文章

  • 基于WPF+Sqlite开发抽奖软件【内附源码】
    在很早之前,就想过开发一款抽奖软件,却一直没有实际去做,最近经过一段时间的准备,终于开发出了一款基于WPF+Sqlite版的抽奖软件,包括客户端和管理端。本项目主要是为了熟悉WPF开发流程,仅供学习分享使用,如有不足之处,还请指正。 涉及知识点 抽奖软件是包括客户端和管理端,在抽奖软件......
  • Containerd-chep3-运行思路
    本文致力于梳理containerd的架构与运行原理。参考文章:https://github.com/containerd/containerd/blob/main/core/runtime/v2/README.mdhttps://www.cnblogs.com/zhangmingcheng/p/17524721.html核心运行思路containerd使用Runtimev2并引入shimAPI,使得containerd可以和很......
  • N 年前,为了学习分库分表,我把 Cobar 源码抄了一遍
    10几年前,互联网产业蓬勃发展,相比传统IT企业,互联网应用每天会产生海量的数据。如何存储和分析这些数据成为了当时技术圈的痛点,彼时,分库分表解决方案应运而生。当时最流行的Java技术论坛是javaeye,有位淘宝的技术人员分享了一篇分库分表的文章,这篇文章,我反复看了几十遍,想从......
  • CyberRT_不同的启动方式的源码解读
    源码解读componentnodereader/writerservice/clientparameterscheduletransportapollo/cyber/cyber.ccCreateNode(){returnstd::unique_ptr<Node>(newNode(node_name,name_space))}apollo/cyber/init.ccInit() OnShutdown()apollo/cyber......
  • Kubernetes:kubelet 源码分析之探针
    0.前言kubernetes提供三种探针,配置探针(Liveness),就绪探针(Readiness)和启动(Startup)探针判断容器健康状态。其中,存活探针确定什么时候重启容器,就绪探针确定容器何时准备好接受流量请求,启动探针判断应用容器何时启动。本文通过分析kubelet源码了解kubernetes的探针是怎么工作......
  • Kubernetes:kubelet 源码分析之 pod 创建流程
    0.前言kubelet是运行在Kubernetes节点上的“节点代理”,用来管理节点。kubelet主要负责所在节点上的资源对象的管理,例如Pod资源对象的创建,删除,监控,驱逐及生命周期管理等。1.kubelet源码分析1.1kubelet模块kubelet包括的模块如下图:从图中可以看出,kubelet的模......
  • 排队叫号系统项目源码开发搭建
    一款基于PHP开发的多项目多场景排队叫号系统,支持大屏幕投屏,语音播报叫号,可用于餐厅排队取餐、美甲店排队取号、排队领取、排队就诊、排队办理业务等诸多场景,助你轻松应对各种排队取号叫号场景。采用GatewayWorker开发完成的 程序开发:PHP+MySQL程序演示:http://jh1.yetukeji.t......
  • cmake以源码的方式引入第三方项目
    最前#本文将介绍一种以源码的方式引入第三方库的方法准备#主项目,需要引用第三方库的某些函数第三方库,以源码的形式提供给主项目使用注意:本文的背景:已经将第三方源码下载好。一个例子#我这里准备一个简单的项目,调用第三方库 fmt;其中fmt是以源码的形式引入项目cmake......
  • MySQL全文索引源码剖析之Insert语句执行过程
    本文分享自华为云社区《MySQL全文索引源码剖析之Insert语句执行过程》,作者:GaussDB数据库。1.背景介绍全文索引是信息检索领域的一种常用的技术手段,用于全文搜索问题,即根据单词,搜索包含该单词的文档,比如在浏览器中输入一个关键词,搜索引擎需要找到所有相关的文档,并且按相关性......
  • lodash已死?radash库方法介绍及源码解析 —— 函数柯里化 + Number篇
    写在前面tips:点赞+收藏=学会!主页有更多其他篇章的方法,欢迎访问查看。本篇我们继续介绍radash中函数柯里化和Number相关的方法使用和源码解析。函数柯里化chain:创建一个函数链并依次执行使用说明功能描述:用于创建一个函数链,该链依次执行一系列函数,每个函数的输出......