K8s 基于 IB RDMA 网络加速大模型分布式训练的部署与测试指南
- 今天
环境说明
本文操作基于以下固定环境配置,执行前需确保集群环境与下述信息一致,或根据实际环境调整对应参数。
- K8s 集群:版本为 v1.23.7,包含 1 个控制节点与 1 个工作节点,已提前安装 Node Feature Discovery(NFD)组件,用于节点硬件特性探测。
- 操作系统:所有节点统一使用 Ubuntu 24.04 LTS 版本,确保系统内核与 IB 驱动兼容性。
- 网络类型:采用 InfiniBand(IB)RDMA 网络,需提前完成物理网卡硬件部署与基础驱动安装。
安装k8s-device-plugin
k8s-device-plugin 用于实现 GPU 资源的容器化调度,需先配置容器运行时,再通过 Helm 部署插件,具体步骤如下。
安装 nvidia-container-toolkit
nvidia-container-toolkit 是 GPU 容器运行的基础依赖,需在所有节点执行安装命令(具体安装命令需参考 NVIDIA 官方文档,根据系统版本选择对应方式)。
配置 Container Runtime
- 执行命令配置 containerd 运行时,指定 nvidia 为 runtime 类型:
sudo nvidia-ctk runtime configure --runtime=containerd
- 编辑 containerd 配置文件,设置默认运行时为 nvidia:
sudo vi /etc/containerd/config.toml
在配置文件中找到以下层级,补充或修改 default_runtime_name 字段:
[plugins]
[plugins."io.containerd.grpc.v1.cri"]
[plugins."io.containerd.grpc.v1.cri".containerd]
default_runtime_name = "nvidia"
- 重启 containerd 服务,使配置生效:
sudo systemctl restart containerd
配置 RuntimeClass
创建 RuntimeClass 资源,用于指定 GPU 容器的运行时,YAML 配置如下:
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: nvidia # RuntimeClass 名称,后续 Pod 可通过此名称指定运行时
handler: nvidia # 与 containerd 中配置的 runtime 名称对应
执行部署命令:kubectl apply -f runtimeclass-nvidia.yaml
安装 k8s-device-plugin
- 为节点添加 GPU 标识标签,便于插件识别 GPU 节点:
kubectl label nodes <节点名称> nvidia.com/gpu.present=true
- 添加 nvidia-device-plugin 的 Helm 仓库:
helm repo add nvdp https://nvidia.github.io/k8s-device-plugin
- 通过 Helm 安装插件,指定版本、镜像地址及关键参数:
helm install nvidia-device-plugin nvdp/nvidia-device-plugin \
--version=0.17.4 \
--namespace nvidia-device-plugin \
--create-namespace \
--set image.repository=swr.cn-east-3.myhuaweicloud.com/lomtom-common/k8s-device-plugin \
--set compatWithCPUManager=true \ # 开启与 CPU Manager 的兼容性,优化资源调度
--set migStrategy=mixed # 支持 GPU MIG(多实例 GPU)模式,灵活分配 GPU 资源
IB RDMA 相关配置与部署
获取 IB 设备信息
在所有节点执行以下命令,获取 IB 网卡厂商 ID、设备 ID 及网卡名称,用于后续配置匹配。
- 查看 IB 网卡型号与 PCI 地址:
lspci | grep Mellanox
输出示例(本文环境使用 Mellanox ConnectX-6/7 系列网卡):
# lspci | grep Mellanox
19:00.0 Infiniband controller: Mellanox Technologies MT2910 Family [ConnectX-7]
3b:00.0 Infiniband controller: Mellanox Technologies MT2910 Family [ConnectX-7]
4c:00.0 Infiniband controller: Mellanox Technologies MT2910 Family [ConnectX-7]
5d:00.0 Infiniband controller: Mellanox Technologies MT2910 Family [ConnectX-7]
9b:00.0 Infiniband controller: Mellanox Technologies MT2910 Family [ConnectX-7]
a8:00.0 Infiniband controller: Mellanox Technologies MT28908 Family [ConnectX-6]
bb:00.0 Infiniband controller: Mellanox Technologies MT2910 Family [ConnectX-7]
cb:00.0 Infiniband controller: Mellanox Technologies MT2910 Family [ConnectX-7]
db:00.0 Infiniband controller: Mellanox Technologies MT2910 Family [ConnectX-7]
- 根据 PCI 地址(如 19:00.0)查询厂商 ID 与设备 ID:
lspci -n | grep 19:00.0
输出示例(需记录厂商 ID 15b3 与设备 ID 1021):
19:00.0 0302: 10de:2335 (rev a1)
创建 RDMA 设备配置 ConfigMap
通过 ConfigMap 定义 RDMA 资源的匹配规则,指定厂商 ID、设备 ID 及网卡名称,YAML 配置如下:
# 1. vendors 匹配 IB 网卡厂商 ID(需与 3.1 步骤获取结果一致)
# 2. deviceIDs 匹配 IB 网卡设备 ID(需与上一步骤获取结果一致)
# 3. ifNames 匹配节点上的 IB 网卡名称(需根据实际环境修改)
apiVersion: v1
kind: ConfigMap
metadata:
name: rdma-devices
namespace: kube-system
data:
config.json: |
{
"periodicUpdateInterval": 300,
"configList": [{
"resourceName": "ib",
"resourcePrefix": "rdma",
"rdmaHcaMax": 1024,
"selectors": {
"vendors": ["15b3"],
"deviceIDs": ["1021"],
"ifNames": ["ibs11", "ibs13", "ibs15", "ibs17"]
}
}
]
}
执行部署命令:kubectl apply -f rdma-devices-configmap.yaml
部署 RDMA 共享设备插件 DaemonSet
通过 DaemonSet 在所有节点部署 RDMA 设备插件,实现 RDMA 资源的探测与分配,YAML 配置如下:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: rdma-shared-dp-ds
namespace: kube-system
spec:
selector:
matchLabels:
name: rdma-shared-dp-ds
template:
metadata:
labels:
name: rdma-shared-dp-ds
spec:
hostNetwork: true
priorityClassName: system-node-critical
containers:
- image: swr.cn-east-3.myhuaweicloud.com/lomtom-common/k8s-rdma-shared-dev-plugin:v1.3.2
name: k8s-rdma-shared-dp-ds
imagePullPolicy: IfNotPresent
securityContext:
privileged: true
volumeMounts:
- name: device-plugin
mountPath: /var/lib/kubelet/device-plugins
readOnly: false
- name: plugins-registry
mountPath: /var/lib/kubelet/plugins_registry
readOnly: false
- name: config
mountPath: /k8s-rdma-shared-dev-plugin
- name: devs
mountPath: /dev/
nodeSelector:
nvidia.com/gpu.deploy.gpu-feature-discovery: "true"
volumes:
- name: device-plugin
hostPath:
path: /var/lib/kubelet/device-plugins
- name: plugins-registry
hostPath:
path: /var/lib/kubelet/plugins_registry
- name: config
configMap:
name: rdma-devices
items:
- key: config.json
path: config.json
- name: devs
hostPath:
path: /dev/
执行部署命令:kubectl apply -f rdma-shared-dp-daemonset.yaml
测试准备
部署测试 Pod(DaemonSet 方式)
通过 DaemonSet 在两个测试节点上创建 Pod,配置 IB 资源、权限及测试工具安装命令,YAML 配置如下:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nginx-rdma
spec:
selector:
matchLabels:
app: nginx
template:
spec:
containers:
- image: swr.cn-east-3.myhuaweicloud.com/lomtom-common/nginx:1.27
name: nginx
securityContext:
capabilities:
add: [ "IPC_LOCK" ]
resources:
limits:
rdma/ib: "1"
command:
- sh
- -c
- |
apt update && apt install -y ibverbs-utils perftest
ls -l /dev/infiniband /sys/class/infiniband /sys/class/net
sleep 100000
执行部署命令:kubectl apply -f nginx-rdma-daemonset.yaml
验证 Pod 状态
部署完成后,通过命令查看 Pod 运行状态与网络信息,确保 Pod 正常启动且分配 IB 资源,并且记录 Pod IP,用于后续测试:
➜ ~ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP
nginx-rdma 1/1 Running 0 4m58s 100.125.224.132
nginx-rdma1 1/1 Running 0 4m58s 100.101.169.137
并且每个 Pod日志都会输出相应的Ib信息:
/dev/infiniband:
total 0
crw------- 1 root root 231, 64 Oct 19 00:05 issm0
crw------- 1 root root 231, 65 Oct 19 00:05 issm1
crw------- 1 root root 231, 66 Oct 19 00:05 issm2
crw------- 1 root root 231, 67 Oct 19 00:05 issm3
crw------- 1 root root 231, 68 Oct 19 00:05 issm4
crw------- 1 root root 231, 70 Oct 19 00:05 issm6
crw------- 1 root root 231, 71 Oct 19 00:05 issm7
crw------- 1 root root 231, 72 Oct 19 00:05 issm8
crw-rw-rw- 1 root root 10, 118 Oct 19 00:05 rdma_cm
crw------- 1 root root 231, 0 Oct 19 00:05 umad0
crw------- 1 root root 231, 1 Oct 19 00:05 umad1
crw------- 1 root root 231, 2 Oct 19 00:05 umad2
crw------- 1 root root 231, 3 Oct 19 00:05 umad3
crw------- 1 root root 231, 4 Oct 19 00:05 umad4
crw------- 1 root root 231, 6 Oct 19 00:05 umad6
crw------- 1 root root 231, 7 Oct 19 00:05 umad7
crw------- 1 root root 231, 8 Oct 19 00:05 umad8
crw-rw-rw- 1 root root 231, 192 Oct 19 00:05 uverbs0
crw-rw-rw- 1 root root 231, 193 Oct 19 00:05 uverbs1
crw-rw-rw- 1 root root 231, 194 Oct 19 00:05 uverbs2
crw-rw-rw- 1 root root 231, 195 Oct 19 00:05 uverbs3
crw-rw-rw- 1 root root 231, 196 Oct 19 00:05 uverbs4
crw-rw-rw- 1 root root 231, 198 Oct 19 00:05 uverbs6
crw-rw-rw- 1 root root 231, 199 Oct 19 00:05 uverbs7
crw-rw-rw- 1 root root 231, 200 Oct 19 00:05 uverbs8
/sys/class/infiniband:
total 0
lrwxrwxrwx 1 root root 0 Oct 14 08:58 mlx5_0 -> ../../devices/pci0000:15/0000:15:01.0/0000:16:00.0/0000:17:01.0/0000:19:00.0/infiniband/mlx5_0
lrwxrwxrwx 1 root root 0 Oct 14 08:58 mlx5_1 -> ../../devices/pci0000:37/0000:37:01.0/0000:38:00.0/0000:39:01.0/0000:3b:00.0/infiniband/mlx5_1
lrwxrwxrwx 1 root root 0 Oct 14 08:58 mlx5_2 -> ../../devices/pci0000:48/0000:48:01.0/0000:49:00.0/0000:4a:01.0/0000:4c:00.0/infiniband/mlx5_2
lrwxrwxrwx 1 root root 0 Oct 14 08:58 mlx5_3 -> ../../devices/pci0000:59/0000:59:01.0/0000:5a:00.0/0000:5b:01.0/0000:5d:00.0/infiniband/mlx5_3
lrwxrwxrwx 1 root root 0 Oct 14 08:58 mlx5_4 -> ../../devices/pci0000:97/0000:97:01.0/0000:98:00.0/0000:99:01.0/0000:9b:00.0/infiniband/mlx5_4
lrwxrwxrwx 1 root root 0 Oct 14 08:58 mlx5_5 -> ../../devices/pci0000:a7/0000:a7:01.0/0000:a8:00.0/infiniband/mlx5_5
lrwxrwxrwx 1 root root 0 Oct 14 08:58 mlx5_6 -> ../../devices/pci0000:b7/0000:b7:01.0/0000:b8:00.0/0000:b9:01.0/0000:bb:00.0/infiniband/mlx5_6
lrwxrwxrwx 1 root root 0 Oct 14 08:58 mlx5_7 -> ../../devices/pci0000:c7/0000:c7:01.0/0000:c8:00.0/0000:c9:01.0/0000:cb:00.0/infiniband/mlx5_7
lrwxrwxrwx 1 root root 0 Oct 14 08:58 mlx5_8 -> ../../devices/pci0000:d7/0000:d7:01.0/0000:d8:00.0/0000:d9:01.0/0000:db:00.0/infiniband/mlx5_8
/sys/class/net:
total 0
-rw-r--r-- 1 root root 4096 Oct 14 08:58 bonding_masters
lrwxrwxrwx 1 root root 0 Oct 14 08:58 eth0 -> ../../devices/virtual/net/eth0
lrwxrwxrwx 1 root root 0 Oct 14 08:58 lo -> ../../devices/virtual/net/lo
lrwxrwxrwx 1 root root 0 Oct 14 08:58 tunl0 -> ../../devices/virtual/net/tunl0
测试步骤
IB RDMA 读取速度测试(ib_read_bw)
- 服务端操作:打开终端 1,进入 IP 为 100.125.224.132 的 Pod(nginx-rdma),执行服务端命令,指定 IB 设备为 mlx5_0,启用所有端口并以 Gb/s 显示结果:
ib_read_bw -a -d mlx5_0 --report_gbits
- 客户端操作:打开终端 2,进入 IP 为 100.101.169.137 的 Pod(nginx-rdma1),执行客户端命令,连接服务端 IP 并保持参数一致:
ib_read_bw -d mlx5_0 --all --report_gbits 100.125.224.132
- 结果查看:待测试完成后,查看服务端输出的 “BW peak [Gb/sec]” 字段,记录读取速度峰值。
IB RDMA 写入速度测试(ib_write_bw)
测试步骤与读取速度测试一致,仅替换测试命令为 ib_write_bw:
- 服务端命令:
ib_write_bw -a -d mlx5_0 --report_gbits - 客户端命令:
ib_write_bw -d mlx5_0 --all --report_gbits 100.125.224.132 - 结果查看:查看服务端输出的 “BW peak [Gb/sec]” 字段,记录写入速度峰值。
IB RDMA 读时延测试(ib_read_lat)
- 服务端操作:打开终端 1,进入 nginx-rdma Pod,执行服务端命令:
ib_read_lat -a -d mlx5_0
- 客户端操作:打开终端 2,进入 nginx-rdma1 Pod,执行客户端命令连接服务端:
ib_read_lat -a -d mlx5_0 100.125.224.132
- 结果查看:查看客户端输出的 “t_avg [usec]” 字段,记录平均读时延。
IB RDMA 写时延测试(ib_write_lat)
测试步骤与读时延测试一致,仅替换测试命令为 ib_write_lat:
- 服务端命令:
ib_write_lat -a -d mlx5_0 - 客户端命令:
ib_write_lat -a -d mlx5_0 100.125.224.132 - 结果查看:查看客户端输出的 “t_avg [usec]” 字段,记录平均写时延。
性能测试结果
| 测试项 | 测试结果 | 指令 |
|---|---|---|
| IB RDMA 读取速度 | BW peak[355.37Gb/s] | ib_read_bw |
| IB RDMA 写入速度 | BW peak[377.32Gb/s] | ib_write_bw |
| IB RDMA 读时延测试 | t_avg[195.17 usec] | ib_read_lat |
| IB RDMA 写时延测试 | t_avg[184.67 usec] | ib_write_lat |