Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Docker及Kubernetes下device使用和分析

Docker及Kubernetes下device使用和分析

原创
作者头像
langwu 吴英文
修改于 2019-09-16 14:14:02
修改于 2019-09-16 14:14:02
10.8K0
举报
文章被收录于专栏:KubernetesKubernetes

Docker下使用device

默认情况下,Docker容器内无法访问宿主机上的设备,比如/dev/mem

Docker有两种方式访问设备,一种是使用特权模式,一种是通过--device指定要访问的设备。

非特权模式下,容器内的root用户相当于宿主机上的普通用户,使用特权模式后,容器内的root用户将真正获得root权限,可以访问很多host上的设备,包括/dev/mem,GPU等

使用特权模式会将一些容器不需要用到的权限也放开,存在较大风险。所以在设备上,一般使用--device来指定容器可使用的设备

需要说明的是,使用--device挂载的设备,容器内的进程通常没有权限操作,需要使用--cap-add开放相应的权限,如下

Kubernetes下使用device

Kubernetes支持--device问题在社区上讨论了很久,感兴趣的可以看下#5607。当前的解决方案是使用device plugins机制来注册要访问的设备,典型的如GPU(https://github.com/NVIDIA/k8s-device-plugin)。同样,如果pod要使用/dev/mem,也需要有一个device plugin将/dev/mem注册到Kubernetes中,注册成功后,可在相应节点中查看到该设备资源信息,这时就可以在pod中使用了。

Kubernetes device plugin设计实现可见https://github.com/kubernetes/community/blob/master/contributors/design-proposals/resource-management/device-plugin.md

由于/dev下有很多的设备,每个device都写一个device plugin确实很麻烦,有一给力的哥们开源了个k8s-hostdev-plugin项目(https://github.com/honkiko/k8s-hostdev-plugin),可基于该项目挂载/dev下的一些设备(该项目当前有个缺陷,后面源码分析会提到)。

下载k8s-hostdev-plugin包,编辑 hostdev-plugin-ds.yaml中的containers.*.args,如下

执行kubectl create -f hostdev-plugin-ds.yaml创建daemonset对象。

当daemonset的pod起来后,执行kubectl describe node检查/dev/mem是否有注册到Kubernetes中。当node的Capacity和Allocatable有hostdev.k8s.io/dev_mem时,说明/dev/mem注册成功

在业务pod中使用/dev/mem,与使用cpu等resource一样。需要注意的是,扩展资源仅支持整型的资源,且容器规格中声明的 limitrequest 必须相等

k8s-hostdev-plugin实现分析

k8s-device-plugin是怎么实现将/dev/mem挂载到容器内的呢?我们先用docker inspect CONTAINERID看pod的容器

和直接用docker run --device跑起来的容器一样。由此可知k8s-device-plugin最终还是基于Docker的--device来指定容器可访问的设备

Kubernetes device plugin API 提供了以下几种方式来设置容器

代码语言:txt
AI代码解释
复制
type ContainerAllocateResponse struct {
	// List of environment variable to be set in the container to access one of more devices.
	Envs map[string]string `protobuf:"bytes,1,rep,name=envs" json:"envs,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
	// Mounts for the container.
	Mounts []*Mount `protobuf:"bytes,2,rep,name=mounts" json:"mounts,omitempty"`
	// Devices for the container.
	Devices []*DeviceSpec `protobuf:"bytes,3,rep,name=devices" json:"devices,omitempty"`
	// Container annotations to pass to the container runtime
	Annotations map[string]string `protobuf:"bytes,4,rep,name=annotations" json:"annotations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
}

其中Envs表示环境变量,如NVIDIA GPU device plugin就是通过这个来指定容器可运行的GPU。Devices则对应容器的--device,k8s-hostdev-plugin就是通过该方式来指定容器可使用的设备。

看下k8s-hostdev-plugin的代码实现

代码语言:txt
AI代码解释
复制
// NewHostDevicePlugin returns an initialized HostDevicePlugin
func NewHostDevicePlugin(devCfg *DevConfig) (*HostDevicePlugin, error) {
	normalizedName, err := NomalizeDevName(devCfg.DevName)
	if err != nil {
		return nil, err
	}

  //要注册到Kubernetes的设备信息
	devs := []*pluginapi.Device {
		&pluginapi.Device{ID: devCfg.DevName, Health: pluginapi.Healthy},
	}

	return &HostDevicePlugin{
		DevName: 		devCfg.DevName,
		Permissions:    devCfg.Permissions,
		NormalizedName: normalizedName,
		ResourceName:   ResourceNamePrefix + normalizedName,
		UnixSockPath:   pluginapi.DevicePluginPath + normalizedName,
		Dev:			devs,
		StopChan: 		make(chan interface{}),
		IsRigistered: false,
	}, nil
}

上面的pluginapi.Device表示一个设备,包含设备ID和设备状态两个字段。需要注意的是,扩展资源仅支持整型的资源,因为这里只new了一个设备,所以最多只能有一个pod能使用这个resource。如果要运行多个使用该resource的pod,可以多new几个pluginapi.Device,确保DeviceID不一样就可以了。(目前该项目还未支持该功能,需要使用者自己去修改扩展)。

k8s-hostdev-plugin向kubelet注册device resource信息后,kubelet会调用ListAndWatch()方法获取所有设备信息。ListAndWatch()将device信息发送给kubelet后,会定时上报device的状态。实现如下

代码语言:txt
AI代码解释
复制
// ListAndWatch lists devices and update that list according to the health status
func (plugin *HostDevicePlugin) ListAndWatch(e *pluginapi.Empty, s pluginapi.DevicePlugin_ListAndWatchServer) error {

	s.Send(&pluginapi.ListAndWatchResponse{Devices: plugin.Dev})

	ticker := time.NewTicker(time.Second * 10)

	for {
		select {
		case <-plugin.StopChan:
			return nil
		case <-ticker.C:
			s.Send(&pluginapi.ListAndWatchResponse{Devices: plugin.Dev})
		}
	}
	return nil
}

当pod的resources.limits中使用该resource时,kubelet会调用Allocate()方法请求资源信息,Allocate()方法可根据请求的DeviceID返回相应的信息。这里因为要将/dev下的设备挂载到容器中,使用了ContainerAllocateResponse.Devices。在pluginapi.DeviceSpec中可指定host和容器的device路径,以及读写权限。具体实现如下

代码语言:txt
AI代码解释
复制
// Allocate which return list of devices.
func (plugin *HostDevicePlugin) Allocate(ctx context.Context, r *pluginapi.AllocateRequest) (*pluginapi.AllocateResponse, error) {
	//spew.Printf("Context: %#v\n", ctx)
	spew.Printf("AllocateRequest: %#v\n", *r)

	response := pluginapi.AllocateResponse{}

  //指定host和容器的device路径,以及读写权限
	devSpec := pluginapi.DeviceSpec {
		HostPath: plugin.DevName,
		ContainerPath: plugin.DevName,
		Permissions: plugin.Permissions,
	}

	//log.Debugf("Request IDs: %v", r)
	var devicesList []*pluginapi.ContainerAllocateResponse

  //构建返回给kubelet的device resource信息
	devicesList = append(devicesList, &pluginapi.ContainerAllocateResponse{
		Envs: make(map[string]string),
		Annotations: make(map[string]string),
		Devices: []*pluginapi.DeviceSpec{&devSpec},
		Mounts: nil,
	})

	response.ContainerResponses = devicesList

	spew.Printf("AllocateResponse: %#v\n", devicesList)

	return &response, nil
}

参考

https://github.com/kubernetes/kubernetes/issues/5607

https://github.com/kubernetes/community/blob/master/contributors/design-proposals/resource-management/device-plugin.md

https://github.com/honkiko/k8s-hostdev-plugin

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
NVIDIA/k8s-device-plugin源码分析
Author: xidianwangtao@gmail.com k8s-device-plugin内部实现原理图 在Kubernetes如何通过Device Plugins来使用NVIDIA GP
Walton
2018/04/18
4.3K2
NVIDIA/k8s-device-plugin源码分析
Kubernetes 多卡GPU使用和分析
Kubernetes中通过device plugin将GPU作为一种resource来使用,因此需要先创建一个device plugin将GPU信息注册到Kubernetes中。NVIDIA官方提供了一个GPU device plugin,详情可见https://github.com/NVIDIA/k8s-device-plugin。
langwu 吴英文
2019/09/01
11.1K1
HAMi源码解析——device-plugin
在介绍 HAMi 的 device-plugin 前,先了解一下 K8s 中的 Pod 是怎么使用 GPU 的。
DifficultWork
2025/06/25
2960
Kubernetes如何通过Devi
Device Plugins Device Pulgins在Kubernetes 1.10中是beta特性,开始于Kubernetes 1.8,用来给第三方设备厂商通过插件化的方式将设备资源对接到Kubernetes,给容器提供Extended Resources。 通过Device Plugins方式,用户不需要改Kubernetes的代码,由第三方设备厂商开发插件,实现Kubernetes Device Plugins的相关接口即可。 目前关注度比较高的Device Plugins实现有: Nvidia
Walton
2018/04/16
1.8K0
Kubernetes如何通过Devi
Kubelet Device Plugin 的工作机制
从Kubernetes 1.8开始,官方推荐使用Device Plugins方式来使用GPU、FPGA、NIC、InfiniBand等高性能硬件。
用户7020774
2020/03/02
5.8K0
Kubelet Deivce Manager源码分析
本文基于Kubernetes v1.10的代码,对Kubelet Device Manager的实现进行了代码走读分析,方便对kubelet与device plugin的交互有更深入的理解。另外,分别对kubelet的Register服务、kubelet调用device plugin的Allocate接口等做了分析,尤其要了解kubelet device plugins的checkpoint机制。
Walton
2018/05/03
2.2K0
Kubelet Deivce Manager源码分析
深度剖析Kubernetes动态准入控制之Admission Webhooks
Author: xidianwangtao@gmail.com Admission Controll的最佳配置 这部分内容,请参考我的上一篇博文深度剖析Kubernetes动态准入控制之Initializers External Admission Webhooks工作机制 External Admission Webhooks有什么用 我们什么时候需要用External Admission Webhooks呢?当集群管理员需要强制对某些请求或者所有请求都进行校验或者修改的时候,就可以考虑使用Vali
Walton
2018/04/16
3.2K0
深入 kubernetes API 的源码实现
很多同学应该像我一样,第一次打开 Github 上面 kubernetes 项目源码的时候就被各种仓库搞晕了,kuberentes 组织下有很多个仓库,包括 kubernetes、client-go、api、apimachinery 等,该从哪儿仓库看起?kubernetes 仓库应该是 kubernetes 项目的核心仓库,它包含 kubernetes 控制平面核心组件的源码;client-go 从名字也不难看出是操作 kubernetes API 的 go 语言客户端;api 与 apimachinery 应该是与 kubernetes API 相关的仓库,但它们俩为啥要分成两个不同的仓库?这些代码仓库之间如何交互?apimachinery 仓库中还有 api、apis 两个包,里面定义了各种复杂的接口与实现,清楚这些复杂接口对于扩展 kubernetes API 大有裨益。所以,这篇文章就重点关注 api 与 apimachinery 这两个仓库。
米开朗基杨
2021/04/02
1.2K0
使用 Elastic GPU 管理 Kubernetes GPU 资源
徐蓓,腾讯云容器技术专家,腾讯云异构计算容器负责人,多年云计算一线架构设计与研发经验,长期深耕 Kubernetes、在离线混部与 GPU 容器化领域,Kubernetes KEP Memory QoS 作者,Kubernetes 积极贡献者。 当前存在问题 GPU 具备大量核心和高速内存,擅长并行计算,非常适合训练和运行机器学习模型。由于近几年 AI 技术愈发成熟,落地场景越来越多,对 GPU 的需求呈井喷趋势。而在资源管理调度平台上,Kubernetes 已成为事实标准。所以很多客户选择在 Kubern
腾讯云原生
2022/04/21
3.5K0
使用 Elastic GPU 管理 Kubernetes GPU 资源
kubernetes GPU管理与Device Plugin机制
Kubernetes 在 Pod 的 API 对象里,并没有为 GPU 专门设置一个资源类型字段,而是使用了一种叫作 Extended Resource(ER)的特殊字段来负责传递 GPU 的信息。
rxg456
2025/03/26
1230
kubernetes GPU管理与Device Plugin机制
Kubrenetes 设备插件详解
Kubernetes 提供了一个 设备插件框架, 你可以用它来将系统硬件资源发布到 Kubelet。
thierryzhou
2022/12/01
1.1K0
基于 Kubernetes 的 GPU 类型调度实现
3 月 27 日,ACM 宣布深度学习的三位缔造者——Yoshua Bengio、Yann LeCun 及 Geoffrey Hinton 获得了 2018 年度的图灵奖。与学术界相对应的,在工业界,人工智能大潮也正汹涌奔来。除了冲击人们的衣食住行医,人工智能也将成为企业转型的颠覆性力量,是企业抓住下一轮创新发展的重要机遇。
kubernetes中文社区
2019/06/24
1.6K0
基于 Kubernetes 的 GPU 类型调度实现
如何为 Kubernetes 定制特性
Kubernetes 是非常复杂的集群编排系统,然而哪怕包含丰富的功能和特性,因为容器的调度和管理本身就有较高的复杂性,所以它无法满足所有场景下的需求。虽然 Kubernetes 能够解决大多数场景中的常见问题,但是为了实现更加灵活的策略,我们需要使用 Kubernetes 提供的扩展能力实现特定目的。
我是阳明
2021/04/26
6000
如何为 Kubernetes 定制特性
kubelet 架构设计解析之 CPU Manager
CPU Manager 是 kubelet 的一个组件,能够让用户给容器分配独占 CPU。CPU Manager 从 Kubernetes v1.10 进入 Beta 阶段, 在 Kubernetes v1.26 中,它进阶至正式发布(GA)状态。
AlphaHinex
2024/04/09
3380
kubelet 架构设计解析之 CPU Manager
原 荐 Kubernetes HPA Con
Author: xidianwangtao@gmail.com 更多关于kubernetes的深入文章,请看我csdn或者oschina的博客主页。 关于kubernetes HPA Controller的工作原理,请参考我这篇博文。 源码目录结构分析 HorizontalPodAutoscaler(以下简称HPA)的主要代码如下,主要涉及的文件不多。 cmd/kube-controller-manager/app/autoscaling.go // HPA Controller的启动代码
Walton
2018/04/13
2K0
原                    荐                                                            Kubernetes HPA Con
如何在Kubernetes集群中利用GPU进行AI训练
Author: xidianwangtao@gmail.com 注意事项 截止Kubernetes 1.8版本: 对GPU的支持还只是实验阶段,仍停留在Alpha特性,意味着还不建议在生产环境中使用Kubernetes管理和调度GPU资源。 只支持NVIDIA GPUs。 Pods不能共用同一块GPU,即使同一个Pod内不同的Containers之间也不能共用同一块GPU。这是Kubernetes目前对GPU支持最难以接受的一点。因为一块PU价格是很昂贵的,一个训练进程通常是无法完全利用满一块GPU的
Walton
2018/04/16
3K0
如何在Kubernetes集群中利用GPU进行AI训练
Kubernetes对象深入学习之三:对象属性
程序员欣宸
2023/07/24
3100
Kubernetes对象深入学习之三:对象属性
在 Kubernetes 实施混沌工程—— Chaos Mesh® 原理分析与控制面开发
Chaos Mesh® 是由 TiDB 背后的 PingCAP 公司开发,运行在 Kubernetes 上的混沌工程(Chaos Engineering)系统。简而言之,Chaos Mesh® 通过运行在 K8s 集群中的“特权”容器,依据 CRD 资源中的测试场景,在集群中制造浑沌(模拟故障)1。
PingCAP
2021/10/27
1.5K0
Containerd NRI 插件
Github:https://github.com/containerd/nri.git
abin
2023/03/21
1.2K0
Containerd NRI 插件
容器能不能将 volume 挂载直接挂到根目录?—— 浅析 kubelet 到 runc 的调用过程
这件事起源于有小伙伴在某群里问,在 K8s 中,能不能把 volume 挂载直接挂到根目录?我的第一反应是不能。容器会使用 union filesystem 将容器的内容挂到根目录下,这点在正常情况下是无法更改的。但是就止于此吗?发现给不出合理解释的时候,突然感觉自己对于容器的认知只停留在了很表面的阶段。
腾讯云 CODING
2023/03/31
1.3K0
容器能不能将 volume 挂载直接挂到根目录?—— 浅析 kubelet 到 runc 的调用过程
相关推荐
NVIDIA/k8s-device-plugin源码分析
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档