containerd 源码分析

containerd 是一个高度模块化的高级运行时,所有模块均以 RPC service 形式加载(gRPC 或者 TTRPC),所有模块均可插拔。不同插件通过声明互相依赖,由 containerd 核心实现统一加载,使用方可以使用 Go 语言实现编写插件实现更丰富的功能。不过这种设计使得 containerd 拥有强大的跨平台能力,并能够作为一个组件轻松嵌入其他软件,也带来一个弊端,模块之间功能互调也从简单的函数调用,变成了更为昂贵的 RPC 调用。

containerd 架构

上图是containerd 官方给出的架构图,可以看出containerd 也是C/S架构,服务器端通过domain socket( 主要用于同一主机上的进程通信,与主机间的进程通信不同,更高效率)暴露gRPC API接口出去,客户端通过这些API管理节点上的容器。每个containerd 只负责一台机器,管理容器的生命周期,拉取推送容器镜像,存储管理(镜像和容器数据的存储),网络实际运行容器是由runc负责。为了解耦,containerd 将系统划分成了不同的组件,每个组件都由一个或多个模块协作完成(Core 部分),每一种类型的模块都以插件的形式集成到 Containerd 中,而且插件之间是相互依赖的,例如,上图中的每一个长虚线的方框都表示一种类型的插件。

CRI

1 引入CRI 的原因

在kubernetes 早期的时候,,Docker 作为第一个容器运行时,Kubelet 通过内嵌的 dockershim 操作 Docker API 来操作容器,进而达到一个面向终态的效果,通过硬编码的方式直接调用Dcker API,后来因为出现多种容器运行时,Kubernetes 为了支持更多精简的容器运行时,Google和RedHat就推出了CRI标准,用于将Kubernetes平台和特定的容器运行时进行解耦。

2 CRI概述

cri是Kubernetes容器运行时接口(CRI)的容器插件实现。有了它,您就可以使用 containerd 作为 Kubernetes 集群的容器运行时。

kubelet 使用gRPC框架同通过Unix套接字与容器运行时发(或运行时的CRI shim)通信,此时kubelet 作为client ,CRI shim 作为server 端。protobuf API包含两个gRPC服务,ImageService和RuntimeService 。 

3 流程图

cri-shim 存在 

        1 .1版本之前对CRI的适配是作为一个单独的cri-container进程(shim)来支持的,因为CRI之初有一些容器运行时可能不会自身就去实现 CRI 接口,于是就有了shim垫片 , 一个 shim 的职责就是作为适配器将各种容器运行时本身的接口适配到 Kubernetes 的 CRI 接口上。

cri-shim 作为插件存在   containerd版本 

cri是containerd的原生插件。从 containerd 1.1 开始,cri 插件内置在发布二进制文件中并默认启用。Kubelet 可以直接调用

 

​一

1. cri插件起gRPC框架服务 runtime.RuntimeServiceServer    runtime.ImageServiceServer

2. init函数注册cri pugin

2. initCRIService 函数配置信息      etc/containerd/config.toml

3. getServicesOpts 函数获取cri 插件上下文获取服务选项实现内部服务

1client.go    

创建一个client 连接到contianerd 的实例

2  service.go    创建一个CRIService实例

3实现了gRPC接口,实现了cri 接口

4启动cri服务

1.Kubelet 通过 CRI runtime service API 调用 cri plugin 创建 pod

2.cri 通过 CNI 创建 pod 的网络配置和 namespace,这里会调用 cni 插件创建 network 等步骤  setup the network for the namespace 

3.cri 使用 containerd 创建并启动 pause container (sandbox container) 并且把这个 container 置于 pod 的 cgroups/namespace(store),其余container 都会和其共享同一个 network namespace

4.Kubelet 接着通过 CRI image service API 调用 cri plugin, 获取容器镜像

5.cri 通过 containerd 获取容器镜像

6.Kubelet 通过 CRI runtime service API 调用 cri, 在 pod 的空间使用拉取的镜像启动容器

7.cri 通过 containerd 创建/启动 应用容器, 并且把 container 置于 pod 的 cgroups/namespace. Pod 完成启动.

4

centOS8 最新版本适配的containerd 版本 

docker 19.03版本适配的containerd 版本

...

附:

存储库

说明

containerd/containerdcontainerd 的主要项目 repo,包括容器运行时
containerd/containerd.io用于构建 containerd 网站和文档的资产(即您当前正在阅读的内容)
containerd/containerd从 containerd 1.5 开始,Kubernetes 容器运行时接口(CRI)的 containerd 插件已合并到 containerd 中。
containerd/项目跨容器存储库使用的实用程序,例如脚本、通用文件和核心文档
containerd/ttrpccontainerd 使用的 gRPC 版本(专为低内存环境设计)

context 包

在 Go 语言编写的服务器程序中,服务器通常要为每个 HTTP 请求创建一个 goroutine 以并发地处理业务。同时,这个 goroutine 也可能会创建更多的 goroutine 来访问数据库或者 RPC 服务。当这个请求超时或者被终止的时候,需要优雅地退出所有衍生的 goroutine,并释放资源。因此,我们需要一种机制来通知衍生 goroutine 请求已被取消。

Context 包提供上下文机制在 goroutine 之间传递 deadline、取消信号(cancellation signals)或者其他请求相关的信息。使用方法是:

  1. 首先,服务器程序为每个接受的请求创建一个 Context 实例(称为根 context,通过 context.Background() 方法创建);
  2. 之后的 goroutine 接受根 context 的一个派生 Context 对象。比如通过调用根 context 的 WithCancel 方法,创建子 context;
  3. goroutine 通过 context.Done() 方法监听取消信号。func Done() <-chan struct{} 是一个通信操作,会阻塞 goroutine,直到收到取消信号接触阻塞。(可以借助 select 语句,如果收到取消信号,就退出 goroutine;否则,默认子句是继续执行 goroutine);
  4. 当一个 Context 被取消(比如执行了 cancelFunc()),那么该 context 派生出来的 context 也会被取消。

//

条件编译允许只编译源文件中满足条件的程序段,使生成的目标程序较短,从而减少了内存的开销,并提高程序的效率,可以按不同的条件编译不同的程序部分,因而产生不同的目标代码文件。 这对于程序的移植和调试很有用的。 [2] 另外,条件编译是为了让程序在各种不同的软硬件环境下都以运行。 即,提高了程序的可移植性和灵活性。

gRPC 是一种现代开源高性能远程过程调用 (RPC) 框架,可以在任何环境中运行。它可以通过对负载平衡、跟踪、健康检查和身份验证的可插拔支持,有效地连接数据中心内和数据中心之间的服务。它还适用于分布式计算的最后一英里,将设备、移动应用程序和浏览器连接到后端服务。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值