kubernetes安装配置使用vGPU

前言

AI 落地时,在某些场景下 AI 模型在训练或者是推理时,其算力要求不需要占用整卡的 GPU,比如只需要0.5卡 GPU 即可满足需求。

在这种情况下,可以使用 GPU 虚拟化技术来解决这个问题,将整卡的 GPU 虚拟化为两个0.5卡的 GPU,这样就可以在一张卡上同时跑两个 AI 训练或者 AI 推理应用服务,极大压榨算力资源,降低成本。

vGPUNVIDIA 提供的一种 GPU 虚拟化的一种方案,同时也可以实现对多用户的强 GPU 隔离方案

基本痛点:

  • 容器使用的单卡 GPU 利用率不够高,特别是推理任务;
  • 为了提高 GPU 的利用率、避免算力浪费,需要在单个 GPU 上运行多个容器
  • vGPU 的使用需要额外从 NVIDIA 公司购买 license。年度订阅和永久许可证

其他vGPU插件

https://github.com/4paradigm/k8s-vgpu-scheduler

4paradigm 提供了 k8s-device-plugin,该插件基于NVIDIA官方插件( NVIDIA/k8s-device-plugin),在保留官方功能的基础上,实现了对物理 GPU 进行切分,并对显存和计算单元进行限制,从而模拟出多张小的 vGPU卡`。

k8s 集群中,基于这些切分后的 vGPU 进行调度,使不同的容器可以安全的共享同一张物理 GPU,提高 GPU 的利用率。

此外,插件还可以对显存做虚拟化处理(使用到的显存可以超过物理上的显存),运行一些超大显存需求的任务,或提高共享的任务数。

部署

配置docker

nvidia-smi命令,查看当前显卡信息

如果你使用了 docker,需要讲将 nvidia runtime 设置为 docker runtime 预设值,此文件通常在 /etc/docker/daemon.json 路径:

复制代码
{
    "default-runtime": "nvidia",
    "runtimes": {
        "nvidia": {
            "path": "/usr/bin/nvidia-container-runtime",
            "runtimeArgs": []
        }
    }
}

docker 重新加载配置

复制代码
systemctl daemon-reload && systemctl restart docker

配置containerd

你需要在节点上将 nvidia runtime 做为你的 containerd runtime 预设值。

我们将编辑 containerd daemon 的配置文件,此文件通常在 /etc/containerd/config.toml 路径

复制代码
version = 2
[plugins]
  [plugins."io.containerd.grpc.v1.cri"]
    [plugins."io.containerd.grpc.v1.cri".containerd]
      default_runtime_name = "nvidia"

      [plugins."io.containerd.grpc.v1.cri".containerd.runtimes]
        [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia]
          privileged_without_host_devices = false
          runtime_engine = ""
          runtime_root = ""
          runtime_type = "io.containerd.runc.v2"
          [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia.options]
            BinaryName = "/usr/bin/nvidia-container-runtime"

containerd 重新加载配置

复制代码
systemctl daemon-reload && systemctl restart containerd

查看当前gpu分配情况

可以通过 kubectl describe node node1命令,查看你指定节点的 gpu 个数情况:

复制代码
Allocatable:
  cpu:                32
  ephemeral-storage:  94059137278
  hugepages-1Gi:      0
  hugepages-2Mi:      0
  memory:             65738804Ki
  nvidia.com/gpu:     2
  pods:               110

关闭NVIDIA官方插件

nvidia-device-plugin ds 描述文件移除即可,为安全可以移动到其它目录,如下移动到家目录做备份保存。

复制代码
mv /etc/kubernetes/manifests/nvidia-device-plugin.yml .

启用新的gpu设备插件

启动 4paradigm 新的 k8s-device-plugin

复制代码
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: nvidia-device-plugin-daemonset
  namespace: kube-system
spec:
  selector:
    matchLabels:
      name: nvidia-device-plugin-ds
  updateStrategy:
    type: RollingUpdate
  template:
    metadata:
      annotations:
        scheduler.alpha.kubernetes.io/critical-pod: ""
      labels:
        name: nvidia-device-plugin-ds
    spec:
      tolerations:
      - key: CriticalAddonsOnly
        operator: Exists
      - key: nvidia.com/gpu
        operator: Exists
        effect: NoSchedule
      priorityClassName: "system-node-critical"
      containers:
      - image: 4pdosc/k8s-device-plugin:latest
        imagePullPolicy: Always
        name: nvidia-device-plugin-ctr
        args: ["--fail-on-init-error=false", "--device-split-count=6", "--device-memory-scaling=2", "--device-cores-scaling=1"]
        env:
        - name: PCIBUSFILE
          value: "/usr/local/vgpu/pciinfo.vgpu"
        - name: NVIDIA_MIG_MONITOR_DEVICES
          value: all
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop: ["ALL"]
            add: ["SYS_ADMIN"]
        volumeMounts:
          - name: device-plugin
            mountPath: /var/lib/kubelet/device-plugins
          - name: vgpu-dir
            mountPath: /usr/local/vgpu
          - mountPath: /tmp
            name: hosttmp
      volumes:
        - name: device-plugin
          hostPath:
            path: /var/lib/kubelet/device-plugins
        - name: vgpu-dir
          hostPath:
            path: /usr/local/vgpu
        - hostPath:
            path: /tmp
          name: hosttmp
      nodeSelector: 
        nvidia-vgpu: "on"

将以上代码保存为 vgpu-nvdp.yaml 文件,然后安装

复制代码
kubectl apply -f vgpu-nvdp.yaml
复制代码
fail-on-init-error:布尔类型, 预设值是 true。当这个参数被设置为 true 时,如果装置插件在初始化过程遇到错误时程序会返回失败,当这个参数被设置为 false 时,遇到错误它会打印信息并且持续阻塞插件。持续阻塞插件能让装置插件即使部署在没有 GPU 的节点(也不应该有 GPU)也不会抛出错误。这样你在部署装置插件在你的集群时就不需要考虑节点是否有 GPU,不会遇到报错的问题。然而,这么做的缺点是如果 GPU 节点的装置插件因为一些原因执行失败,将不容易察觉。现在预设值为当初始化遇到错误时程序返回失败,这个做法应该被所有全新的部署采纳。

device-split-count:整数类型,预设值是 2。NVIDIA 装置的分割数。对于一个总共包含N张 NVIDIA GPU 的 Kubernetes 集群,如果我们将device-split-count参数配置为K,这个 Kubernetes 集群将有K * N个可分配的 vGPU 资源。注意,我们不建议将 NVIDIA 1080 ti/NVIDIA 2080 tidevice-split-count参数配置超过 5,将 NVIDIA T4 配置超过 7,将 NVIDIA A100 配置超过 15。

device-memory-scaling:浮点数类型,预设值是 1。NVIDIA 装置显存使用比例,可以大于 1(启用虚拟显存,实验功能)。对于有M显存大小的 NVIDIA GPU,如果我们配置device-memory-scaling参数为S,在部署了我们装置插件的 Kubenetes 集群中,这张 GPU 分出的 vGPU 将总共包含S * M显存。每张 vGPU 的显存大小也受device-split-count参数影响。在先前的例子中,如果device-split-count参数配置为K,那每一张 vGPU 最后会取得S * M / K大小的显存。

device-cores-scaling:浮点数类型,预设值是 1。NVIDIA 装置算力使用比例,可以大于 1。如果device-cores-scaling参数配置为Sdevice-split-count参数配置为K,那每一张 vGPU 对应的一段时间内 sm 利用率平均上限为S / K。属于同一张物理 GPU 上的所有 vGPU sm 利用率总和不超过 1。

enable-legacy-preferred:布尔类型,预设值是 false。对于不支持 PreferredAllocation 的 kublet(<1.19)可以设置为 true,更好的选择合适的 device,开启时,本插件需要有对 pod 的读取权限,可参看 legacy-preferred-nvidia-device-plugin.yml。对于 kubelet >= 1.9 时,建议关闭。

打上gpu标签

在需要进行虚拟化的节点打上标签 nvidia-vgpu:"on" ,否则该节点不会被调度到,或者你打其他标签也行,取决于你设置的 nodeSelector

复制代码
kubectl label node {nodeid} nvdia-vgpu=on

等插件部署完成后,再次执行 kubectl describe node node1命令,查看节点的 gpu 个数情况

运行GPU任务

NVIDIA vGPUs 现在能透过资源类型 nvidia.com/gpu 被容器请求:

复制代码
apiVersion: v1
kind: Pod
metadata:
  name: gpu-pod
spec:
  containers:
    - name: ubuntu-container
      image: ubuntu:18.04
      command: ["bash", "-c", "sleep 86400"]
      resources:
        limits:
          nvidia.com/gpu: 2 # 请求2个vGPUs
	  nvidia.com/gpumem: 3000 # 每个vGPU申请3000m显存 (可选,整数类型)
	  nvidia.com/gpucores: 30 # 每个vGPU的算力为30%实际显卡的算力 (可选,整数类型)

如果你的任务无法运行在任何一个节点上(例如任务的 nvidia.com/gpu 大于集群中任意一个 GPU 节点的实际 GPU 数量),那么任务会卡在 pending 状态

现在你可以在容器执行 nvidia-smi 命令,然后比较 vGPU 和实际 GPU 显存大小的不同。

监控vGPU使用情况

调度器部署成功后,监控默认自动开启,你可以通过

复制代码
http://{nodeip}:{monitorPort}/metrics

来获取监控数据,其中 monitorPort 可以在 Values 中进行配置,默认为 31992

grafana dashboard 示例:https://github.com/4paradigm/k8s-vgpu-scheduler/blob/master/docs/dashboard_cn.md

注意 节点上的 vGPU 状态只有在其使用 vGPU 后才会被统计 W

posted @   牛奔  阅读(1034)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· [翻译] 为什么 Tracebit 用 C# 开发
· Deepseek官网太卡,教你白嫖阿里云的Deepseek-R1满血版
· 2分钟学会 DeepSeek API,竟然比官方更好用!
· .NET 使用 DeepSeek R1 开发智能 AI 客户端
· 刚刚!百度搜索“换脑”引爆AI圈,正式接入DeepSeek R1满血版
点击右上角即可分享
微信分享提示