从监控到隔离,阿里云容器服务提升您的GPU资源使用体验
推动人工智能不断向前的动力来自于强大的算力,海量的数据和优化的算法,而Nvidia GPU是最流行的异构算力提供者,是高性能深度学习的基石。但是GPU不菲的价格一直是用户的心头之痛,而从使用率的角度来看,模型预测场景下,应用独占GPU模式实际上会对这种宝贵的资源造成大量的浪费。但是共享GPU实际上也不是一蹴而就,比如一方面用户需要判断多少的分配GPU资源可以达到成本和QPS平衡的最优,另一方面也要考虑同时当多个应用运行在一个GPU设备上时,应用的SLA如何保障。
而通过使用阿里云容器服务,一方面借助托管的Prometheus,提升GPU资源管理的可见性,快速了解到需要多少的GPU资源可以支撑图像识别,语音识别,在线翻译等业务,如何能用最少的成本满足业务需求;而另一方面,借助昊天cGPU,在无需修改现有GPU程序的前提下,保障多个容器共享同一个GPU时,彼此互相隔离。
我们通过一个实际的例子向您展示如何利用托管Prometheus的监控能力查看GPU的显存使用,并且通过昊天cGPU进行资源隔离。
前置条件
- 标准专有GPU集群 1.16.6,不支持托管版GPU集群
- docker版本 >= 19.03.5
- 开通 ARMS
- 主账号为arms-prometheus功能授权
- 支持GPU硬件: telsa P4、telsa P100、 telsa T4 、telsa v100(16GB)
使用步骤
通过托管Prometheus监控独享GPU
- 登录ARMS控制台, 选择Kubernetes所在的集群
- 在ARMS控制台中Prometheus界面中,点击集群列表中需要监控集群的安装按钮。此过程需要2分钟左右,请点击确认。
- 在该集群的已安装插件中可以看到
GPU Node
和GPU APP
,分别从节点维度和应用维度监控GPU资源
- 运行测试应用
利用命令行部署如下应用, 参考文档
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: app-3g-v1
labels:
app: app-3g-v1
spec:
replicas: 1
serviceName: "app-3g-v1"
podManagementPolicy: "Parallel"
selector: # define how the deployment finds the pods it manages
matchLabels:
app: app-3g-v1
updateStrategy:
type: RollingUpdate
template: # define the pods specifications
metadata:
labels:
app: app-3g-v1
spec:
containers:
- name: app-3g-v1
image: registry.cn-shanghai.aliyuncs.com/tensorflow-samples/cuda-malloc:3G
resources:
limits:
nvidia.com/gpu: 1
部署成功后,查看应用的状态,可以知道应用的名称是app-3g-v1-0
kubectl get po
NAME READY STATUS RESTARTS AGE
app-3g-v1-0 1/1 Running 1 2m56s
- 通过应用角度监控, 点击
GPU App
进入可以观察到GPU的显存使用率, 可以发现这个应用的GPU显存占用率仅为20%,有80%的浪费。而它使用的显存也是比较稳定在3.4GB左右,而该GPU总的显存是16GB左右。
此时可以发现一个应用独占一张GPU卡的模式非常浪费。因此可以考虑通过使用cGPU(container GPU)可以将多个应用部署在同一个GPU卡上。
可以先将该容器移除
kubectl delete sts app-3g-v1
使用cGPU保障多容器共享
为带有GPU设备的节点打标签
在安装cGPU相关组件之前,需要给gpu节点打上标签"cgpu=true",步骤如下:
(1)登录容器服务 Kubernetes 版控制台。
(2)在 Kubernetes 菜单下,单击左侧导航栏中的集群 > 节点,进入节点列表页面。选择所需的集群,在页面右上角单击标签管理。
(3)选择所需的集群,在页面右上角单击标签管理。
(4)在节点列表中,批量选择节点,然后单击添加标签。
(5)填写标签名称和值(名称为cgpu,值为true),点击确定。
安装cGPU相关组件
(1)登录容器服务 Kubernetes 版控制台。(2)在左侧导航栏选择市场 > 应用目录,在右侧选中 ack-cgpu。(3)在应用目录 -> ack-cgpu页面上,在右侧的创建面板中选择前提条件中创建的集群和命名空间,并单击创建。
- 安装kubectl-inspect-cgpu
kubectl-inspect-gpushare是一个查询节点GPU分配情况的工具,它依赖集群的kubeconfig配置文件。请登录到linux客户端进行安装。请确保"~/.kube/config"文件已经存在,如何下载集群的kubeconfig文件,请参考用kubectl管理集群。kubeconfig文件配置完成以后,接着在该节点上执行如下操作安装kubectl-inspect-cgpu:
# cd /usr/local/bin
# wget http://aliacs-k8s-cn-beijing.oss-cn-beijing.aliyuncs.com/cgpu/kubectl-inspect-cgpu
# chmod u+x /usr/local/bin/kubectl-inspect-cgpu
- 通过kubectl-inspect-cgpu检查GPU资源
# kubectl inspect cgpu
NAME IPADDRESS GPU0(Allocated/Total) GPU Memory(GiB)
cn-hangzhou.192.168.2.167 192.168.2.167 0/15 0/15
----------------------------------------------------------------------
Allocated/Total GPU Memory In Cluster:
0/15 (0%)
此时可以发现该节点的GPU资源维度已经从卡变成GPU显存
部署共享GPU工作负载
- 按照GPU显存维度调度重新创建工作负载
只需要将之前的部署yaml做两处的修改:
- 将实例的副本数从1改为2,这样可以指定部署两个负载。而在原有GPU独享的配置下,单个GPU卡智能调度单个容器;修改配置后,可以部署两个Pod实例。
- 将资源维度从
nvidia.com/gpu
变为aliyun.com/gpu-mem
, 单位也从个变成了GiB
由于每个应用不足以独享GPU资源,因此它们可以部署到同一个GPU设备上。
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: app-3g-v1
labels:
app: app-3g-v1
spec:
replicas: 2
serviceName: "app-3g-v1"
podManagementPolicy: "Parallel"
selector: # define how the deployment finds the pods it manages
matchLabels:
app: app-3g-v1
template: # define the pods specifications
metadata:
labels:
app: app-3g-v1
spec:
containers:
- name: app-3g-v1
image: registry.cn-shanghai.aliyuncs.com/tensorflow-samples/cuda-malloc:3G
resources:
limits:
aliyun.com/gpu-mem: 4
从运行结果看,可以看到两个Pod都运行在同一个GPU设备上
# kubectl inspect cgpu -d
NAME: cn-hangzhou.192.168.2.167
IPADDRESS: 192.168.2.167
NAME NAMESPACE GPU0(Allocated)
app-3g-v1-0 default 4
app-3g-v1-1 default 4
Allocated : 8 (53%)
Total : 15
--------------------------------------------------------
Allocated/Total GPU Memory In Cluster: 8/15 (53%)
- 而分别登陆两个容器的时候可以看到他们各自的GPU显存的上限已经设置为4301MiB, 也就是在容器内使用的GPU显存不会超过这个上限
kubectl exec -it app-3g-v1-0 nvidia-smi
Mon Apr 13 01:33:10 2020
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 418.87.01 Driver Version: 418.87.01 CUDA Version: 10.1 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 Tesla V100-SXM2... On | 00000000:00:07.0 Off | 0 |
| N/A 37C P0 57W / 300W | 3193MiB / 4301MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
+-----------------------------------------------------------------------------+
kubectl exec -it app-3g-v1-1 nvidia-smi
Mon Apr 13 01:36:07 2020
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 418.87.01 Driver Version: 418.87.01 CUDA Version: 10.1 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 Tesla V100-SXM2... On | 00000000:00:07.0 Off | 0 |
| N/A 38C P0 57W / 300W | 3193MiB / 4301MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
+-----------------------------------------------------------------------------+
- 而登陆到节点后,可以看到该GPU被使用的显存资源为两个容器之和6396MiB。这里可以看到cGPU资源已经起到了按容器隔离的效果。
# nvidia-smi
Mon Apr 13 09:36:43 2020
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 418.87.01 Driver Version: 418.87.01 CUDA Version: 10.1 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 Tesla V100-SXM2... On | 00000000:00:07.0 Off | 0 |
| N/A 37C P0 57W / 300W | 6396MiB / 16130MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| 0 2174 C cuda_malloc 3193MiB |
| 0 2209 C cuda_malloc 3193MiB |
+-----------------------------------------------------------------------------+
- 此时登录到容器内试图申请更多的GPU资源时,会直接报出显存分配失败的错误
kubectl exec -it app-3g-v1-1 bash
root@app-3g-v1-1:/# cuda_malloc -size=1024
cgpu_cuda_malloc starting...
Detected 1 CUDA Capable device(s)
Device 0: "Tesla V100-SXM2-16GB"
CUDA Driver Version / Runtime Version 10.1 / 10.1
Total amount of global memory: 4301 MBytes (4509925376 bytes)
Try to malloc 1024 MBytes memory on GPU 0
CUDA error at cgpu_cuda_malloc.cu:119 code=2(cudaErrorMemoryAllocation) "cudaMalloc( (void**)&dev_c, malloc_size)"
通过托管Prometheus监控共享GPU
- 实际上用户并不需要到每个容器内执行nvidia-smi,这样做监控一方面效率低,也无法获得资源趋势。用户可以通过登录到ARMS控制台,选择相应的Kubernetes集群,进入
GPU App
。可以直接看到每个应用的GPU显存用量和占比
- 如果希望从节点维度观测,可以通过
GPU Node
查看GPU卡的显存使用量。可以看到恰好其显存使用率是两个GPU应用的使用之和为40%。
- 接下来,我们演示如何将一个害群之马关到笼子里,即当某个应用程序的声明使用GPU显存用量超过了资源上限后,cGPU如何确保当其他应用不受影响。
部署一个新的GPU应用,该应用声明使用的GPU显存是4GiB,但是它实际使用的GPU显存为6GiB
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: app-6g-v1
labels:
app: app-6g-v1
spec:
replicas: 1
serviceName: "app-6g-v1"
podManagementPolicy: "Parallel"
selector: # define how the deployment finds the pods it manages
matchLabels:
app: app-6g-v1
template: # define the pods specifications
metadata:
labels:
app: app-6g-v1
spec:
containers:
- name: app-6g-v1
image: registry.cn-shanghai.aliyuncs.com/tensorflow-samples/cuda-malloc:6G
resources:
limits:
aliyun.com/gpu-mem: 4
将该应用部署之后可以发现该pod一直处于CrashLoopBackOff
, 而之前两个Pod还是正常运行的状态
# kubectl get po
NAME READY STATUS RESTARTS AGE
app-3g-v1-0 1/1 Running 0 7h35m
app-3g-v1-1 1/1 Running 0 7h35m
app-6g-v1-0 0/1 CrashLoopBackOff 5 3m15s
而该容器的日志报错,也很明确的显示是由于cudaErrorMemoryAllocation造成的
kubectl logs app-6g-v1-0
CUDA error at cgpu_cuda_malloc.cu:119 code=2(cudaErrorMemoryAllocation) "cudaMalloc( (void**)&dev_c, malloc_size)"
而此时其他的容器并没有收到影响,从托管的Prometheus监控中也可以看到之前的容器一直处于平稳运行之中,并没有受到新部署应用的影响。
总结
通过使用阿里云容器服务的GPU支持,可以提升GPU资源管理的可见性,了解到需要多少的GPU资源可以支撑图像识别,语音识别,在线翻译等业务,如何能用最少的成本满足业务需求;而可以在无需修改现有GPU程序的前提下,保障多个容器共享同一个GPU时,实现彼此互相隔离。帮助用户在享受低成本的同时,保障了应用的可靠性。