Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Docker及Kubernetes下device使用和分析

Docker及Kubernetes下device使用和分析

原创
作者头像
langwu 吴英文
修改于 2019-09-16 14:14:02
修改于 2019-09-16 14:14:02
10.8K1
举报
文章被收录于专栏: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 删除。

评论
登录后参与评论
1 条评论
热度
最新
赞,学习了
赞,学习了
回复回复点赞举报
推荐阅读
编辑精选文章
换一批
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
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如何通过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.9K0
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源码分析
HAMi源码解析——device-plugin
在介绍 HAMi 的 device-plugin 前,先了解一下 K8s 中的 Pod 是怎么使用 GPU 的。
DifficultWork
2025/06/25
4050
Kubrenetes 设备插件详解
Kubernetes 提供了一个 设备插件框架, 你可以用它来将系统硬件资源发布到 Kubelet。
thierryzhou
2022/12/01
1.1K0
容器开启特权模式后无法通过cadvisor获取GPU metrics指标
开启特权模式(--privileged)的容器,在使用nvidia GPU时,无法通过cAdvisor获取GPU相关的metrics信息。Google大法可以搜到相关的Issue,于2018年提出,至今仍处于Open状态(给cAdvisor贡献代码的机会),由于涉及到的内容较多,分为三篇来讲。
李鹤
2023/03/28
5160
容器开启特权模式后无法通过cadvisor获取GPU metrics指标
kubernetes GPU管理与Device Plugin机制
Kubernetes 在 Pod 的 API 对象里,并没有为 GPU 专门设置一个资源类型字段,而是使用了一种叫作 Extended Resource(ER)的特殊字段来负责传递 GPU 的信息。
rxg456
2025/03/26
1710
kubernetes GPU管理与Device Plugin机制
如何为 Kubernetes 定制特性
Kubernetes 是非常复杂的集群编排系统,然而哪怕包含丰富的功能和特性,因为容器的调度和管理本身就有较高的复杂性,所以它无法满足所有场景下的需求。虽然 Kubernetes 能够解决大多数场景中的常见问题,但是为了实现更加灵活的策略,我们需要使用 Kubernetes 提供的扩展能力实现特定目的。
我是阳明
2021/04/26
6200
如何为 Kubernetes 定制特性
使用 Elastic GPU 管理 Kubernetes GPU 资源
徐蓓,腾讯云容器技术专家,腾讯云异构计算容器负责人,多年云计算一线架构设计与研发经验,长期深耕 Kubernetes、在离线混部与 GPU 容器化领域,Kubernetes KEP Memory QoS 作者,Kubernetes 积极贡献者。 当前存在问题 GPU 具备大量核心和高速内存,擅长并行计算,非常适合训练和运行机器学习模型。由于近几年 AI 技术愈发成熟,落地场景越来越多,对 GPU 的需求呈井喷趋势。而在资源管理调度平台上,Kubernetes 已成为事实标准。所以很多客户选择在 Kubern
腾讯云原生
2022/04/21
3.6K0
使用 Elastic GPU 管理 Kubernetes GPU 资源
深入 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.3K0
Kubernetes对象深入学习之三:对象属性
程序员欣宸
2023/07/24
3260
Kubernetes对象深入学习之三:对象属性
Containerd NRI 插件
Github:https://github.com/containerd/nri.git
abin
2023/03/21
1.2K0
Containerd NRI 插件
如何在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超越RBAC – 通过Webhook自定义授权
Kubernetes 是一个很棒的容器编排工具,它提供了许多自定义选项。您可以轻松地扩展/替换它的许多…
云云众生s
2024/09/12
2170
Kubernetes超越RBAC – 通过Webhook自定义授权
Kubernetes 新玩法:在 YAML 中编程
那么如何做性能测试?要么是通过编码的方式完成,写一堆脚本,用完即弃;要么是基于平台,在平台定义的流程中进行。对于后者,通常由于目标场景的复杂性,如部署特定的 workload、观测特定的性能项、网络访问问题等,往往导致性能测试平台要以高成本才能满足不断变化的开发场景的需求。
我是阳明
2020/09/24
1K0
Kubernetes 新玩法:在 YAML 中编程
原 荐 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
容器能不能将 volume 挂载直接挂到根目录?—— 浅析 kubelet 到 runc 的调用过程
这件事起源于有小伙伴在某群里问,在 K8s 中,能不能把 volume 挂载直接挂到根目录?我的第一反应是不能。容器会使用 union filesystem 将容器的内容挂到根目录下,这点在正常情况下是无法更改的。但是就止于此吗?发现给不出合理解释的时候,突然感觉自己对于容器的认知只停留在了很表面的阶段。
腾讯云 CODING
2023/03/31
1.4K0
容器能不能将 volume 挂载直接挂到根目录?—— 浅析 kubelet 到 runc 的调用过程
彻底解决pvc无法mount的问题
上周解决pvc无法mount的问题,其实留了一个尾巴,当时只是知道由于未知的原因,AttachDetachController执行detach操作失败了。这周这个问题又出现了,这次追查了一下根源,这里记录下。
jeremyxu
2019/07/23
7.1K2
相关推荐
Kubernetes 多卡GPU使用和分析
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档