引言
在之前的文章中,我们介绍了IT基础架构对于机器学习的重要性,以及如何基于成熟的软件定义数据中心架构进行扩展,从而构建机器学习云平台。(如有需要,请参看:VMware云平台加速机器学习。)
本文中,我们做一些比较深入的技术探讨。重点在基于vRealize Automation实现GPU/vGPU的自动化调度。
这不是一份设计文档,但是会覆盖关键的技术点。读者应该具备一定的vRealize Automation的基本知识,并且具备一定的二次开发能力,以充分理解并且可以在项目中实现。如果您还没有这样的能力,强烈建议参加使用VMware Hands on Lab在线实验进行学习。
概述
vRealize Automation基本逻辑架构
首先,我们还是看一下vRealize Automation的基本逻辑架构。
图1:vRealize Automation的基本逻辑架构
vRA包含两个基本的组件:Appliance和IaaS Component. 其中Appliance是一个经过定制和裁剪之后的Linux,通过ova文件直接导入vSphere就可以了。IaaS Component是一个基于Windows的VM,需要管理员自行安装其中的组件。
我们在架构图中可以看到,Appliance组件主要包含User Interface,VIDM,PostgreSQL和vRO。其中,User Interface(UI)顾名思义,就是负责用户界面。VIDM是一个统一身份管理组件,全称叫VMware Identity Manager,vIDM会对接AD进行身份管理。IaaS组件包含一个很重要的模块叫“Distributed Execution Manager(DEM)”,这个组件负责和vSphere进行集成,并完成虚拟机的部署工作。
一个最简单的执行流程就是: UI驱动DEM,DEM驱动vSphere,实现整个部署过程。
基于vRealize Automation的扩展
以上流程是系统内置的,但是vRA提供了一些可以定制化的“hook”。具体就是通过vRO(vRealize Orchestrator)来实现。vRO是一个工作流平台,我们需要在vRO上面创建一系列工作流(Workflow),以支持在某个VM上面增加、删除或者修改GPU设置。并且通过系统配置,让系统知道在适当的时候调用这些工作流。这样的系统配置包括两种方式:(1)通过在蓝图中设置XaaS;(2)通过Event Broker Service(EBS)触发。关于vRA定制的全面而详细的文档,可以参看VMware官方文档:Life Cycle Extensibility
具体到机器学习云平台,我们需要做的扩展包括:
- 在Blueprint中增加一个XaaS的组件,在虚拟机部署完成之后,执行GPU增加的vRO workflow。
- 增加一个Action操作,并且关联到相应的Blueprint,可以执行GPU变更的vRO workflow。
- 在EBS中增加一个Subscription,当虚拟机被删除的时候,执行GPU删除的vRO workflow。(可能会有疑问,当VM都被删除了,GPU的配置为什么还需要额外做一次删除呢?稍后会提到)
由于vRO只是一个工作流平台,所谓工作流,是没有状态(Stateless)的,而且主要作为集成用途,业务逻辑不宜过于复杂。所以,我们增加了一个组件,用于GPU的调度,这个GPU Scheduler组件作为一个应用独立运行。vRO通过Restful Web Service调用GPU Scheduler组件,进行GPU的申请、变更和回收,这也就是上面第3点提到的,即使VM被删除之后,依然需要调用GPU Scheduler,以回收GPU的注册信息。架构如下图所示:
图2:vRO调用GPU Scheduler
下面,我们就这几个具体的技术要点做阐述。包括:
- GPU Scheduler
- 虚拟机部署过程中的GPU加载
- 虚拟机部署完成之后,进行的GPU变更
- 虚拟机被删除之后,进行的GPU回收
GPU Scheduler
Rest API定义
GPU Scheduler的接口至少应该包含以下两个:Update GPU,Delete GPU
Update GPU:HTTP PUT /vms/<vm-id>/gpus
Request Body:
{
“model”: “P40 / V100 / TitanV / grid_p40-8q”
“number”: 2
}
其中,model可以是P40、V100、TitanV这样的直通模式的配置,也可以是grid_p40-8q这样的vGPU配置。当model为vGPU时,在当前的vSphere版本(6.5)中,只支持1个vGPU,所以number这个数量就不重要了,可以省略。
Response body:
{
“host”: “host01.corp.local”,
“gpuId”: [“0000:04:00.0”, “0000:05:00.0”]
}
其中当request为vGPU申请时,gpuId无需设置。
Delete GPU:HTTP DELETE /vms/<vm-id>/gpus
无论是Update还是Delete操作,都应当是幂等的,以提供较好的容错性。
GPU Scheduler应用架构
GPU Scheduler模块的应用架构应该很简单,基本上需要一个提供Rest服务的Web前端,以及一个数据库。具体的语言和数据库的选择,大家可以各显神通,用自己熟悉的程序设计语言、REST框架和数据库来实现。但是,其中有几点和GPU相关的说明。
- 如果一台物理服务器包含多块CPU和GPU,比如下图中,有两块CPU和8块GPU,他们之间的关系是这样的。当某一台VM申请两块GPU卡,我们尽量分配在同一侧,比如GPU1+GPU2,这样GPU1和GPU2之间的通信不需要跨越CPU,性能会比较好。
图3:GPU连接示意图
- 由于存在申请大数量GPU的情况,比如一台VM需要4块GPU,甚至8块GPU卡。在这种情况,可能存在虽然整个资源池有足够的GPU,但是分布在不同的服务器上,导致没有一台服务器有足够的卡分给这台VM。直通方式的GPU不支持vMotion,所以,很难在不停机的情况下,在线进行碎片整理。所以,在制定分配策略的时候,需要充分考虑。
- 并发必须充分考虑
虚拟机部署过程中的GPU加载
我们将会介绍三个重点:(1)vRA的蓝图;(2)vRO workflow;(3)参数的传递
蓝图
在vRealize Automation平台中,所有的部署都是通过蓝图(blueprint)来实现的。我们来看一下下面这个blueprint。
图4:包含GPU的蓝图
这个blueprint包含两个重要部分,一部分是vSphere和其中的网络配置,另一部分是一个Add GPU的操作。vSphere部分是最常见的配置,在此我们不做赘述。我们重点看一下Add GPU的vRO workflow。
vRO workflow
下图是vRealize Orchestrator中的workflow截图。
图5:更新GPU的vRO Workflow
我们具体看一下,每一步的工作。
- Validate and Transform Parameters:vRA的蓝图传递过来的参数需要做一些校验和转换。
- Power off VM in need:所有的GPU的配置操作都需要VM在停机状态下执行,所以确保VM是停机的。
- Allocate GPU:这一步操作,实际上就是通过Rest API去调用GPU Scheduler,去申请GPU。
- Remove all GPUs from VM:删除VM当前所有的GPU配置,这步操作主要用在变更GPU的时候,但是即使是一台没有GPU配置的VM,也不会发生错误。
- Migrate VM:将VM迁移到GPU Scheduler分配的ESXi host上面。
- Attach GPUs to VM:进行VM配置的变更。
- Start VM:启动VM,并等待vmtools正常运行。
其中,我们重点看一下第6步的代码:
- var vmSpec = new VcVirtualMachineConfigSpec();
- var myDeviceChanges = [];
- for (var i = 0; i < gpuIdsArray.length; i++) {
- var gpuId = gpuIdsArray[i];
- var change = new VcVirtualDeviceConfigSpec();
- change.operation = VcVirtualDeviceConfigSpecOperation.add;
- change.device = new VcVirtualPCIPassthrough();
- change.device.backing = new VcVirtualPCIPassthroughDeviceBackingInfo();
- change.device.backing.deviceId = System.getModule(“xxx.yyy”).getGpuDeviceId(vm.runtime.host, gpuId).toString(16);
- change.device.backing.systemId = vm.environmentBrowser.queryConfigTarget(null).pciPassthrough[0].systemId;
- change.device.backing.deviceName = “PCI device ” + i;
- change.device.backing.vendorId = NVIDIA_VENDOR_ID;
- change.device.backing.id = gpuId;
- myDeviceChanges.push(change);
- }
- vmSpec.deviceChange = myDeviceChanges;
- vmSpec.memoryReservationLockedToMax = true;
- var task = vm.reconfigVM_Task(vmSpec);
需要特别说明的几点:
- 不管是GPU直通还是vGPU模式,VM的内存都需要全部预留,否则VM可能启动会失败,参看第17行。
- 第9行,我们调用了一个vRO的action去获得一个参数deviceId。这个action的内容其实也很简单,拷贝如下,供大家参考:
for each (device in host.hardware.pciDevice){
if (device.id == gpuId){
return device.deviceId;
}
}
如果是vGPU,相关的示例代码如下:
var vmSpec = new VcVirtualMachineConfigSpec();
var myDeviceChanges = [];
var change = new VcVirtualDeviceConfigSpec();
change.operation = VcVirtualDeviceConfigSpecOperation.add;
change.device = new VcVirtualPCIPassthrough();
change.device.backing = new VcVirtualPCIPassthroughVmiopBackingInfo();
change.device.backing.vgpu = vGpuProfile;
myDeviceChanges.push(change);
vmSpec.deviceChange = myDeviceChanges;
vmSpec.memoryReservationLockedToMax = true;
var task = vm.reconfigVM_Task(vmSpec);
当然,这样的workflow并没有考虑到异常处理,在实际生产中,应充分考虑。比如,vRO到GPU Scheduler的通信异常,GPU Scheduler的异常返回。在当前的workflow中,出现任何异常都导致整个申请失败,新创建的VM最终会被删除,这样的行为是否符合用户预期,需要具体情况具体分析。
参数传递
参数传递包括几个阶段,(1)用户从Web界面输入参数 (2)参数保存到vSphere VM的Custom Property中 (3)参数传递到XaaS所代表的vRO工作流。
这里面,重点需要理解Custom Property。Custom Property,顾名思义,就是自定义的一些属性。对于一个VM来说,CPU、memory、磁盘、网络… 这些都是系统自带的属性,但是GPU配置并没有。所以,我们就自定义一个这样的属性。如下图所示,我们定义了两个属性com.vmware.demo.GpuModel和com.vmware.demo.GpuNumber。
图6:用于记录GPU信息的Custom Property
这个参数,我们需要在用户界面上面显示出来,让用户进行输入。最简单的方法就是用系统默认的表单展示,如下图所示:
图7:系统自带的用户界面表单
当然,这种做法从审美的角度可能有些用户不喜欢。另外一种做法就是通过自定义表单(Custom Form)来实现。比如下面这张图。
图8:自定义表单
Custom Property,以及VM的相关信息,最终需要传递到vRO的workflow中。具体我们可以参看一下下面这三张截图,分别传递的是VM的名称、GPU Model和GPU number。
图9:蓝图到XaaS的参数传递
虚拟机部署完成之后,进行的GPU变更
GPU的变更通过vRA提供的Action操作完成。每一个Action对应一个vRO workflow,其实,GPU的变更Workflow和GPU的增加workflow非常类似,只是在输入参数方面有一些差别。
我们先看一下VM部署过程中增加GPU的vRO workflow的参数。
图10:增加GPU vRO workflow输入参数
我们比较一下VM部署之后变更GPU的vRO workflow的参数。
图11:变更GPU vRO workflow输入参数
虚拟机被删除之后,进行的GPU回收
当虚拟机的生命周期结束,被删除之后,原则上说,虚拟机本身的GPU配置是不需要做额外的删除,但是GPU Scheduler中的配置需要变更,否则GPU Scheduler会认为这些分配出去的GPU依然在被使用。这个回收的工作流相对简单,只需要调用GPU Scheduler的HTTP DELETE操作即可。但是,何时触发这个操作,需要用到vRealize Automation提供的Event Broker Service。我们简单看一下,这一块的具体配置,如下图所示:
图12:事件订阅的条件
这三条关系分别如下:
- Data > Lifecycle state > Lifecycle state name = VMPSMasterWorkflow32.Disposing
- Data > Lifecycle state > State phase = PRE
- Data > Machine > Machine Type = Virtual Machine
其三条条件之间是AND的关系,当同时满足,vRO工作流被触发。这个vRO工作流的参数是payload,如下图所示。这个payload中包含所有的事件信息。
图13:事件触发workflow的输入参数
总结
至此,基于vRealize Automation的机器学习云平台的实现方法大致介绍完毕。Again,这不是一个完整的设计方案,只是包含了设计思路和关键技术点。如果您对vRealize Automation比较了解,并具备一定的编程能力,应该能够很快完成实现。祝大家好运!
作者:
韩亮 VMware资深解决方案架构师
姚晨锴 VMware资深技术顾问
龚华 VMware资深解决方案架构师