背景
随着人工智能的兴起,GPU作为重要的智算算力类型愈发受到重视,而Kubernetes(k8s)作为业界主流的集群管理系统,如何方便管理、使用GPU也是其需要解决的一大问题,故此收集整理了K8s管理与使用GPU的相关资料以学习。
物理机如何使用GPU
如果给一台普通的物理机,例如我们日常用的笔记本电脑应该如何使用GPU呢。其主要涉及到两个插件的安装,分别是Nvidia Driver和CUDA Toolkit。
Nvidia Driver
Nvidia Driver就是GPU驱动,其与其他驱动类似,其主要作用是作为操作系统与GPU硬件之间沟通的桥梁,它需要负责将GPU复杂的硬件功能抽象为标准化接口,方便操作系统和软件调用,并能把GPU硬件的反馈结果传递给操作系统或应用程序。
Cuda Toolkit
Cuda toolkit是NVIDIA提供的一个开发工具集,包含了一系列用于GPU编程的工具和库。其主要由以下组件组成:
- Compiler: CUDA-C和CUDA-C++编译器NVCC位于bin/目录中。它建立在NVVM优化器之上,而NVVM优化器本身构建在LLVM编译器基础结构之上。希望开发人员可以使用nvm/目录下的Compiler SDK来直接针对NVVM进行开发。
- Tools: 提供一些像profiler,debuggers等工具,这些工具可以从bin/目录中获取
- Libraries: 下面列出的部分科学库和实用程序库可以在lib/目录中使用(Windows上的DLL位于bin/中),它们的接口在include/目录中可获取。
- cudart: CUDA Runtime
- cudadevrt: CUDA device runtime
- cupti: CUDA profiling tools interface
- nvml: NVIDIA management library
- nvrtc: CUDA runtime compilation
- cublas: BLAS (Basic Linear Algebra Subprograms,基础线性代数程序集)
- cublas_device: BLAS kernel interface
- …
- Runtime Api:提供GPU访问的接口,包括:
- CUDA Runtime API: 提供简单易用的高层接口,简化GPU的初始化和资源管理。
- CUDA Driver API: 更底层的接口,提供对GPU的精细控制,适合需要自定义优化的高级用户。
- CUDA Samples: 演示如何使用各种CUDA和library API的代码示例。可在Linux和Mac上的samples/目录中获得,Windows上的路径是
C:\ProgramData\NVIDIA Corporation\CUDA Samples
中。在Linux和Mac上,samples/
目录是只读的,如果要对它们进行修改,则必须将这些示例复制到另一个位置。
说明
安装完以上插件后就可以使用GPU了,我们可以直接使用CUDA来编程也可以利用Pytorch、TensorFlow等机器学习库来间接使用GPU,在使用GPU时,其整体的调用链如下图所示:
Docker如何使用GPU
配置nvidia-container-runtime
正常创建一个容器的流程是这样的:
简单来说主要有以下这些步骤:
- 用户命令传递: CLI 将用户命令解析并使用 HTTP 或 Unix Socket 与 dockerd 通信。
- 调度与管理: dockerd 解析命令并检查、拉取镜像,再调用 containerd 创建一个新的容器任务,准备容器的元数据和配置(如挂载点、网络设置、环境变量等),并为每个任务创建一个 containerd-shim 进程
- 隔离与启动: containerd-shim 启动并调用 runc 创建隔离环境,runc 从 containerd 提供的配置中读取容器规格,包括文件系统挂载、网络命名空间、cgroups 配置(限制 CPU、内存等资源),并配置PID、Network、Mount Namespace级别的隔离,再配置 Cgroups,限制资源使用,设置 rootfs,将镜像内容挂载为容器的根文件系统。
- 容器运行: runc 启动用户指定的进程,容器进入运行状态。
而为了能够让容器也能直接使用GPU,我们就需要修改创建容器的关键runtime为nvidia-container-runtime,而我们一般都通过NVIDIA Container Toolkit来安装nvidia-container-runtime。旧版本修改runtime为nvidia-container-runtime是需要手动在etc/docker/daemon.json
中增加配置,指定使用 nvidia 的 runtime,如下:
"runtimes": {
"nvidia": {
"args": [],
"path": "nvidia-container-runtime"
}
}
新版 toolkit 带了一个nvidia-ctk 工具,执行以下命令即可一键配置:
sudo nvidia-ctk runtime configure --runtime=docker
然后重启 Docker 即可,再创建使用GPU的容器时,只需要加入--gpu
参数即可,如docker run --rm --gpus all nvidia/cuda:12.0.1-runtime-ubuntu22.04 nvidia-smi
。
说明
修改runtime后,如下图所示,containerd-shim会调用指定的运行时nvidia-container-runtime。nvidia-container-runtime相比于默认的runc多实现了nvidia-container-runime-hook,该hook是在容器启动后(Namespace已创建完成),容器自定义命令(Entrypoint)启动前执行。当检测到NVIDIA_VISIBLE_DEVICES环境变量时,会调用libnvidia-container挂载GPU Device和CUDA Driver。如果没有检测到NVIDIA_VISIBLE_DEVICES就直接执行默认的runc。
在Docker 环境中的 CUDA 调用的整体层级如下图所示,NVIDIA 将原来 CUDA 应用依赖的API环境划分为两个部分:
- 驱动级API:由libcuda.so.major.minor动态库和内核module提供支持,图中表示为CUDA Driver,它必须在宿主机上就配置好,且只能有一个版本。