共计 2313 个字符,预计需要花费 6 分钟才能阅读完成。
本文基于 kubernetes1.25.4 版本,所有代码援用为了简洁都去掉了日志打印相干的代码,尽量只保留有价值的内容。
首先,咱们先看看官网对 device-plugins 的定义是什么?
Starting in version 1.8, Kubernetes provides a device plugin framework for vendors to advertise their resources to the kubelet without changing Kubernetes core code. Instead of writing custom Kubernetes code, vendors can implement a device plugin that can be deployed manually or as a DaemonSet. The targeted devices include GPUs, High-performance NICs, FPGAs, InfiniBand, and other similar computing resources that may require vendor specific initialization and setup.
大略意思是:从 kubernetes1.8 版本开始,提供了设施插件框架,设施厂商无需批改 kubernetes 外围代码就能够将本人生产的设施的资源 (kubernetes 可治理的资源包含 CPU、内存和存储资源) 能够让 kubelet 应用(这一点与操作系统一样,所有设施厂商本人实现驱动)。设施厂商能够本人人工或者以 DaemonSet 形式部署,而不是定制 kubernetes 代码。指标设施包含 GPU、高性能 NIC(网络接口卡)、FPGA、InfiniBand 以及其余相似的须要厂商指定初始化和装置的计算资源。上文援用自 kubernetes 官网文档,读者能够自行理解一下官网对于 device-plugin 的阐明,如下图所示(用图比链接好,放心链接当前会变):
理解 device-plugin 的是什么了,接下来就是看看 kubernetes 是如何实现并工作的。我写这篇文章的外围目标是理解 kubernetes 如何治理 GPU 的,因为我的我的项目须要一个集群同时治理 CPU 和 GPU,依据用户的需要抉择适合的资源计算。所以,前面所有的剖析都是以 GPU 为例,读者如果须要理解其余类型的设施依据本文的思路自行剖析即可。
好了,咱们能够进入正题了。让咱们先遗记一部分内容,看看上面这个图:
如果我作为 kubernetes 开发者,思路是由 kubelet 汇总所有的资源,而后在汇总到治理端,kubernetes 也就是 apiserver。当创立 Pod 时,申请会发送给 scheduler,scheduler 依据节点状态抉择一个最优的节点,最初由最优节点的 kubelet 创立这个 Pod。嗯,这个思路应该没什么大故障,至多我开发的一个分布式计算零碎采纳的就是这个形式,没问题!好,咱们先假如这个想法是就是 kubernetes 的设计方案,此处咱们不讲内存、CPU、存储这些资源是 kubelet 是怎么获取的,因为本文的重点是 device-plugins,咱们只说 GPU 这个 kubelet 是怎么获取的。
下面说到了,kubernetes 有设施插件框架,那这个框架又是什么样的呢?说白了也很简略,就是 kubernetes 定义了一套机制和接口,各设施厂商依照协定开发就能够了,这个和 Linux 驱动原理是一样的,只是实现形式不一样而已。咱们来看看 kubernetes 是怎么实现的,首先咱们先说说机制:
- 厂商自行实现一个治理设施资源的程序,部署到相应的节点上,咱们称之为插件;
- 插件须要向 kubelet 注册,注册内容要蕴含本人的 endpoint(endpoint 就是一个用于通信的地址)以及一些其余信息(前面会阐明);
- kubelet 连贯插件的 endpoint,就此 kubelet 和插件就建设了分割;
- kubelet 监听 /var/lib/kubelet/device-plugins/kubelet.sock(unix sockets)这个地址,插件监听的也是相似的地址,只是地址变成了 /var/lib/kubelet/device-plugins/gpu.sock(举个例子)
以上是插件如何让 kubernetes 发现自己,接下来就是插件和 kubelet 之间的通信接口了。
kubelet 与插件采纳 grpc 通信,通信接口定义在
kubernetes/pkg/kubelet/apis/deviceplugin/v1beta1/api.proto
service Registration {rpc Register(RegisterRequest) returns (Empty) {}}
service DevicePlugin {rpc GetDevicePluginOptions(Empty) returns (DevicePluginOptions) {}
rpc ListAndWatch(Empty) returns (stream ListAndWatchResponse) {}
rpc GetPreferredAllocation(PreferredAllocationRequest) returns (PreferredAllocationResponse) {}
rpc Allocate(AllocateRequest) returns (AllocateResponse) {}
rpc PreStartContainer(PreStartContainerRequest) returns (PreStartContainerResponse) {}}