阿里云容器服务Kubernetes版(ACK)通过托管的Prometheus,可以提升GPU资源管理的可见性。通过昊天cGPU,在无需修改现有GPU程序的前提下,保障多个容器共享同一个GPU时,实现彼此互相隔离。本文以实际示例介绍如何通过托管的Prometheus查看GPU的显存使用,以及如何通过昊天cGPU实现资源隔离。
前提条件
- GPU集群为标准专有版,且Kubernetes版本不低于1.16。
- 开通和升级ARMS。
- 使用主账号登录RAM控制台,为主账号授权arms-prometheus功能。
- GPU硬件为telsa P4、telsa P100、 telsa T4或telsa v100(16 GB)。
背景信息
推动人工智能不断向前的动力来自于强大的算力、海量的数据和优化的算法,而Nvidia GPU是最流行的异构算力提供者,是高性能深度学习的基石。GPU的价格不菲,从使用率的角度来看,模型预测场景下,应用独占GPU模式会造成计算资源的浪费。共享GPU模式可以提升资源利用率,但需要考虑如何达到成本和QPS平衡的最优,以及如何保障应用的SLA。
通过托管Prometheus监控独享GPU
- 登录ARMS控制台。
- 在左侧导航栏中,单击Prometheus监控。
- 在Prometheus监控页面中,选择集群所在地域,然后单击目标集群操作列的安装。
- 在确认对话框中,单击确认。
插件安装过程需要2分钟左右。安装插件完毕后,已安装插件列中将显示全部已安装的插件。
- 通过命令行部署以下示例应用,详情请参见通过命令管理应用。
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显存占用率仅为20%,存在80%的浪费。而它使用的显存稳定在3.4 GB左右,而总显存为16 GB左右。因此一个应用独占一张GPU卡的模式比较浪费,可以考虑通过使用cGPU(container
GPU)将多个应用部署在同一个GPU卡上。

实现多容器共享cGPU
- 为带有GPU设备的节点打标签。
- 登录容器服务管理控制台。
- 在控制台左侧导航栏中,单击集群。
- 在集群列表页面中,单击目标集群名称或者目标集群右侧操作列下的应用管理。
- 在集群管理页左侧导航栏中,单击节点管理。
- 在节点管理页面,单击页面右上角标签与污点管理。
- 在标签与污点管理页面中,批量选择Worker节点,然后单击添加标签。
- 在添加对话框中,填写指定的标签名称和值(标签的名称为cgpu,值为true),单击确定。

注意 如果某个Worker节点设置了标签为cgpu=true,那么该节点将不再拥有独享gpu资源nvidia.com/gpu;如果该节点需要关闭gpu共享功能,请设置标签cgpu的值为false,同时该节点将重新拥有独享gpu资源nvidia.com/gpu。
- 安装cGPU相关组件。
- 登录容器服务管理控制台。
- 在左侧导航栏中,选择,然后在右侧单击ack-cgpu。
- 在右侧的创建面板中选择前提条件中创建的集群和命名空间,并单击创建。
- 登录Master节点并执行以下命令查看GPU资源。
登录Master节点相关步骤,请参见通过kubectl连接Kubernetes集群。
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。
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
- 按照GPU显存维度调度重新创建工作负载。
从运行结果看,两个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显存的上限已经设置为4301 MiB, 也就是在容器内使用的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的使用情况。
可以看到该GPU被使用的显存资源为两个容器之和,即6396 MiB,因此cGPU资源已经实现了按容器隔离的效果。如果此时登录到容器内尝试申请更多的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)"
您可以通过
ARMS控制台,从应用和节点两个维度来监控GPU的使用量。
- GPU APP:可以查看每个应用的GPU显存用量和占比。

- GPU Node:可以查看GPU卡的显存使用量。

使用托管Prometheus来监控共享GPU
当某个应用声明的GPU显存使用量超过了资源上限后,cGPU可以确保其他应用不受影响。
- 部署一个新的GPU应用。
该应用声明使用的GPU显存是4 GiB,但是它实际使用的GPU显存为6 GiB。
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的状态。
新应用的pod一直处于
CrashLoopBackOff,而之前两个Pod还是正常运行的状态。
kubectl get pod
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 APP组件来查看容器状态。
可以看到之前的容器一直处于平稳运行之中,并没有受到新部署应用的影响。

在文档使用中是否遇到以下问题
更多建议
匿名提交