容器服务支持通过组件使用 RDMA 资源,以消除传统网络通信带给计算任务的瓶颈。本文为您介绍 VKE 集群如何使用 RDMA 资源。
说明
【公测】:VKE 集群中使用 RDMA 资源 功能处于公测阶段。
RDMA (Remote Direct Memroy Access,远程直接内存访问)是一种高性能网络协议,能够减少了CPU 占用,减少内存带宽瓶颈,提高带宽利用率。主要具有以下优势:
RDMA 与 mGPU 不能同时使用。
RDMA 目前提供 exclusive(独占)、shared(共享)、shared-multi(1:N 共享)3 种模式。不同模式的使用限制如下:
模式 | 说明 | 使用限制 |
---|---|---|
exclusive(独占) | 将 RDMA 物理网卡直接透传给容器集群中的 Pod 使用,适用于物理设备无法虚拟化切割的场景。 | exclusive 模式暂不支持在 vePFS 场景中使用。 |
shared(共享) | 将 RDMA 物理网卡进行虚拟化切割,创建成 1 张共享虚拟网卡,提供给容器集群中的 Pod 使用。 | shared 模式中,每张 RDMA 物理网卡仅允许创建 1 张共享虚拟网卡。 |
shared-multi(1:N 共享) | 将 RDMA 物理网卡进行虚拟化切切割,按需创建成多张共享虚拟网卡,提供给容器集群中的 Pod 使用。 | shared-multi 模式不建议与 GPU 一起使用。 |
RDMA 设备仅支持在 VPC-CNI 容器网络模型场景中使用,且集群网络组件vpc-cni
要求使用 v1.7.1 及以上版本。
集群 Kubernetes 版本要求 v1.24.15-vke.12 及以上的 1.24 版本;v1.20.15-vke.18 及以上的 1.20 版本。可前往控制台的集群基本信息页面查看,详细介绍参见:如何查看集群的 Kubernetes 版本?
推荐新建容器服务集群和节点池使用 RDMA 资源,详细使用步骤如下。
说明
本步骤仅针对使用 RDMA 资源的关键配置进行详细介绍,包括:创建节点池、添加节点标签、配置 Kubelet 自定义参数、安装 RDMA 组件。创建集群的操作步骤和详细配置参见:创建集群。
集群配置步骤的关键配置项如下,其他参数按需配置即可。
配置项 | 说明 |
---|---|
容器网络模型 | 配置集群的容器网络(CNI)方案,本场景必须选择 VPC-CNI。
|
节点池配置步骤的关键配置项如下,其他参数按需配置即可。
配置项 | 说明 |
---|---|
Worker 节点 | 为确保集群可以正常使用,本场景选择 立即创建。 |
节点来源 | 节点的来源,本场景选择 创建节点。 |
计算规格 | 计算规格用于定义节点 CPU、内存、GPU、RDMA 等参数,本场景需要选择具备 RDMA 设备的计算规格,例如:高性能计算 GPU 型。 |
节点标签 | 对应 Kubernetes 中的 Label,能够为节点定义不同的属性,方便批量筛选等需求,可为节点池中的节点批量添加相同标签。 注意
|
Kubelet 自定义参数 | 针对时延敏感性较高的业务,提供 Kubelet 自定义参数,用于配置 NUMA 亲和策略,可将为 Container (或 Pod) 分配的资源对齐到一个 (或多个) NUMA 上,从而提高业务的性能。 |
rdma-device-plugin
组件,其他组件按需配置即可。完成后单击 下一步:确认配置。上述新建集群完成后,即可在创建工作负载时使用 RDMA 资源,本场景以无状态工作负载为例进行介绍。
说明
为了能够发挥最佳性能,推荐 RDMA 卡数配置为:2 或 4。
Yaml 方式使用 RDMA 资源的说明如下:
vke.volcengine.com/rdma
,同时在 Pod 的 Annotation 中配置对应数量的 pod networks。大部分情况下,容器需要同时申请 IPC_LOCK 特权。示例如下:说明
以下示例以自动创建 1 张网卡设备为例,如需创建多张网卡设备,要求将k8s.volcengine.com/pod-networks
中的如下代码块复制 N 份。
{ "cniConf":{ "name":"rdma" } }
apiVersion: v1 kind: Pod metadata: annotations: k8s.volcengine.com/pod-networks: | [ { "cniConf":{ "name":"rdma" } } ] spec: containers: resources: limits: vke.volcengine.com/rdma: 1 securityContext: capabilities: add: - IPC_LOCK
source nccl_env.sh
命令获取 RDMA 环境变量。动态获取 NCCL 环境变量的参考示例脚本nccl_env.sh
内容如下。#!/usr/bin/env bash devs=() ports=() idxes=() rdmaIdx="" rdmaRate="" rdmaErr="" function scan_devices() { allocDevs=() for d in $(ls /sys/class/infiniband/) ; do allocDevs+=($d) done for d in "${allocDevs[@]}" ; do for p in $(ls /sys/class/infiniband/$d/ports/) ; do for g in $(ls /sys/class/infiniband/$d/ports/$p/gids/) ; do gid=$(cat /sys/class/infiniband/$d/ports/$p/gids/$g); if [ $(echo $gid | cut -d ":" -f -1) != "0000" ] ; then continue fi if [ $gid = 0000:0000:0000:0000:0000:0000:0000:0000 ] ; then continue fi RoCEVer=$(cat /sys/class/infiniband/$d/ports/$p/gid_attrs/types/$g 2>/dev/null| grep -o "[Vv].*") if [ ${RoCEVer,,} != "v2" ]; then continue fi # device not Up ethDev=$(cat /sys/class/infiniband/$d/ports/$p/gid_attrs/ndevs/$g 2>/dev/null) if [[ ! -f /sys/class/net/$ethDev/dev_id ]] || [[ ! -f /sys/class/net/$ethDev/carrier ]] || (( ! $(cat /sys/class/net/$ethDev/carrier 2> /dev/null) == 1 )); then continue fi devs+=($d) ports+=($p) idxes+=($g) done #g (gid) done #p (port) done #d (dev) if [[ -z $devs ]]; then echo "Not found RDMA device, list devices error" return 1 fi } function export_nccl_env() { scan_devices if [[ -z $devs ]]; then echo "Not found RDMA device, get max rate device error" return 1 fi for ((i=0; i<${#devs[@]}; i+=1)); do rate=$(cat /sys/class/infiniband/${devs[i]}/ports/${ports[i]}/rate 2>/dev/null|cut -f 1 -d " ") if [[ -z "$rdmaRate" ]] || [[ "$rate" -gt "$rdmaRate" ]]; then rdmaDevs=(${devs[i]}) rdmaPorts=(${ports[i]}) rdmaIdx=${idxes[i]} rdmaErr="" rdmaRate=$rate elif [[ "$rate" == "$rdmaRate" ]]; then rdmaDevs+=(${devs[i]}) rdmaPorts+=(${ports[i]}) if [[ "$rdmaIdx" != "${idxes[i]}" ]]; then rdmaErr="rdma devs index inconsistent" fi fi done if [[ -n $rdmaErr ]]; then echo $rdmaErr return 1 fi hca=() for ((i=0; i<${#rdmaDevs[@]}; i+=1)); do hca+=("${rdmaDevs[i]}:${rdmaPorts[i]}") done IFS="," export NCCL_IB_HCA=${hca[*]} unset IFS export NCCL_IB_GID_INDEX=$rdmaIdx } export_nccl_env
已经创建容器服务集群和节点池的情况下,可参考以下步骤,直接在存量 VKE 集群和节点池中使用 RDMA 资源。
rdma-device-plugin
组件。...
中的 安装,为集群安装 RDMA 设备插件。需要准备支持 RDMA 设备的节点(例如:高性能计算 GPU 型),可新建或使用存量符合要求的节点。并通过手动添加vke.node.rdma.mode: {value}
标签方式为节点或节点池配置 RDMA 使用模式,支持:exclusive(独占)、shared(共享)、shared-multi(1:N 共享)。
注意
...
中的 标签管理。Yaml 示例如下:
type: Node label: vke.node.rdma.mode: shared status: capacity: vke.volcengine.com/rdma: 4
通过节点池自定义参数配置将 RDMA 节点拓扑管理策略修改为topologyManagerPolicy: best-effort
,确保 GPU 和 RDMA 分配在同一个 NUMA 下。
警告
在存量节点池中修改 kubelet 自定义参数时,默认仅对新增节点生效,不对存量节点生效。如果需要对存量节点生效,则需要执行存量节点参数同步操作,详情请参见 存量节点参数同步。
Yaml 示例如下:
topologyManagerPolicy: best-effort
上述配置完成后,即可在创建工作负载时使用 RDMA 资源,本场景以无状态工作负载为例进行介绍。
说明
为了能够发挥最佳性能,推荐 RDMA 卡数配置为:2 或 4。
Yaml 方式使用 RDMA 资源的说明如下:
vke.volcengine.com/rdma
,同时在 Pod 的 Annotation 中配置对应数量的 pod networks。大部分情况下,容器需要同时申请 IPC_LOCK 特权。示例如下:说明
以下示例以自动创建 1 张网卡设备为例,如需创建多张网卡设备,要求将k8s.volcengine.com/pod-networks
中的如下代码块复制 N 份。
{ "cniConf":{ "name":"rdma" } }
apiVersion: v1 kind: Pod metadata: annotations: k8s.volcengine.com/pod-networks: | [ { "cniConf":{ "name":"rdma" } } ] spec: containers: resources: limits: vke.volcengine.com/rdma: 1 securityContext: capabilities: add: - IPC_LOCK
source nccl_env.sh
命令获取 RDMA 环境变量。动态获取 NCCL 环境变量的参考示例脚本nccl_env.sh
内容如下。#!/usr/bin/env bash devs=() ports=() idxes=() rdmaIdx="" rdmaRate="" rdmaErr="" function scan_devices() { allocDevs=() for d in $(ls /sys/class/infiniband/) ; do allocDevs+=($d) done for d in "${allocDevs[@]}" ; do for p in $(ls /sys/class/infiniband/$d/ports/) ; do for g in $(ls /sys/class/infiniband/$d/ports/$p/gids/) ; do gid=$(cat /sys/class/infiniband/$d/ports/$p/gids/$g); if [ $(echo $gid | cut -d ":" -f -1) != "0000" ] ; then continue fi if [ $gid = 0000:0000:0000:0000:0000:0000:0000:0000 ] ; then continue fi RoCEVer=$(cat /sys/class/infiniband/$d/ports/$p/gid_attrs/types/$g 2>/dev/null| grep -o "[Vv].*") if [ ${RoCEVer,,} != "v2" ]; then continue fi # device not Up ethDev=$(cat /sys/class/infiniband/$d/ports/$p/gid_attrs/ndevs/$g 2>/dev/null) if [[ ! -f /sys/class/net/$ethDev/dev_id ]] || [[ ! -f /sys/class/net/$ethDev/carrier ]] || (( ! $(cat /sys/class/net/$ethDev/carrier 2> /dev/null) == 1 )); then continue fi devs+=($d) ports+=($p) idxes+=($g) done #g (gid) done #p (port) done #d (dev) if [[ -z $devs ]]; then echo "Not found RDMA device, list devices error" return 1 fi } function export_nccl_env() { scan_devices if [[ -z $devs ]]; then echo "Not found RDMA device, get max rate device error" return 1 fi for ((i=0; i<${#devs[@]}; i+=1)); do rate=$(cat /sys/class/infiniband/${devs[i]}/ports/${ports[i]}/rate 2>/dev/null|cut -f 1 -d " ") if [[ -z "$rdmaRate" ]] || [[ "$rate" -gt "$rdmaRate" ]]; then rdmaDevs=(${devs[i]}) rdmaPorts=(${ports[i]}) rdmaIdx=${idxes[i]} rdmaErr="" rdmaRate=$rate elif [[ "$rate" == "$rdmaRate" ]]; then rdmaDevs+=(${devs[i]}) rdmaPorts+=(${ports[i]}) if [[ "$rdmaIdx" != "${idxes[i]}" ]]; then rdmaErr="rdma devs index inconsistent" fi fi done if [[ -n $rdmaErr ]]; then echo $rdmaErr return 1 fi hca=() for ((i=0; i<${#rdmaDevs[@]}; i+=1)); do hca+=("${rdmaDevs[i]}:${rdmaPorts[i]}") done IFS="," export NCCL_IB_HCA=${hca[*]} unset IFS export NCCL_IB_GID_INDEX=$rdmaIdx } export_nccl_env
可根据 RDMA 监控数据中提供的指标确认分配的 RDMA 资源是否已经被使用,RDMA 监控查看方法参见:AI 资源观测 或 查看实例 GPU/RDMA 监控数据。