物理机环境
物理机中要使用上 GPU 需要安装以下组件:
GPU DriverCUDA Toolkit
二者的关系如 NVIDIA 官网 所示:
容器环境
Docker容器中的GPU调用流程图
从图中可以看到,CUDA Toolkit 跑到容器里了,因此宿主机上不需要再安装 CUDA Toolkit。
容器镜像里安装 CUDA Toolkit
容器启动到GPU挂载的完整链路
┌─────────────────────────────────────────────────────────────────┐
│ docker run --gpus all nvidia/cuda nvidia-smi │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ Docker/containerd │
│ ├── 读取:Image Spec(拉取 nvidia/cuda 镜像) │
│ ├── 生成:rootfs(解压合并 layers) │
│ ├── 生成:Runtime Spec(config.json) │
│ └── 输出:Runtime Bundle + OCI Hook 配置(调用 nvidia hook) │
│ (或配置使用 nvidia-container-runtime 作为 runtime) │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ nvidia-container-runtime-hook(或 nvidia-container-runtime) │
│ ├── 读取:Runtime Bundle(config.json + rootfs) │
│ ├── 检测:NVIDIA_VISIBLE_DEVICES 环境变量 │
│ ├── 调用:libnvidia-container.so │
│ │ └── 扫描 /dev/nvidia*,查找 libcuda.so 等 │
│ └── 修改:config.json(注入 mounts、devices、env) │
│ 输出:修改后的 Runtime Bundle(含 GPU 配置) │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ runc │
│ ├── 读取:修改后的 Runtime Bundle │
│ ├── 创建:namespaces, cgroups │
│ ├── 挂载:GPU 设备、驱动库到容器内 │
│ └── 执行:nvidia-smi(容器进程) │
└─────────────────────────────────────────────────────────────────┘
Bundle
Bundle 就是 OCI Runtime Spec 的物理实现。是 runc 等 OCI 运行时的唯一输入,
OCI 规范定义了两个核心标准:
| OCI 规范 | 定义内容 | 实际产物 |
|---|---|---|
| OCI Image Spec | 镜像格式标准(manifest、layers、config) | 镜像文件(可分发、存储) |
| OCI Runtime Spec | 容器运行时的标准配置 | Bundle(config.json + rootfs) |
my-bundle/ ← Bundle 根目录
├── config.json ← Runtime Spec(容器配置)
└── rootfs/ ← 根文件系统
├── bin/
│ ├── sh
│ ├── ls
│ └── nvidia-smi ← GPU 应用二进制
├── etc/
│ ├── passwd
│ └── hostname
├── usr/
│ └── lib/
│ └── x86_64-linux-gnu/
│ ├── libcuda.so
│ └── libcudart.so
├── dev/ ← 运行时挂载
├── proc/ ← 运行时挂载
└── sys/ ← 运行时挂载
应用使用GPU的调用链路
-
libcudart.so 供 User-GPU-Application 侧的框架使用,封装成框架方法给用户调用
-
libcuda.so 承上启下,解释libcudart.so的接口,翻译给nvidia.ko去操作GPU硬件
CUDA Toolkit 可以由容器镜像内提供,而 libcuda.so 通常由宿主机通过挂载方式注入容器。 镜像中还可能包含 compat 目录下的兼容库 libcuda.so,它作为用户态的兼容桥接层,可在需要时优先于宿主机提供的默认 libcuda.so 被加载,并最终与内核态的 nvidia.ko 协同完成 GPU 访问。
该机制使得较新的 CUDA Runtime 在满足最低驱动要求的前提下,能够尽可能运行于较老的宿主驱动环境中;但它并不等价于对所有新特性的完整软件模拟,也不能保证老驱动不支持的能力都能被完全补齐。