在配置AI实验环境或GPU服务器时,您会经常看到这样的命令。
docker run --gpus all nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi
或者,在Kubernetes环境中,您需要在GPU节点上安装NVIDIA驱动,配置NVIDIA Container Toolkit,然后运行需要GPU的容器。
这自然会引出一个问题:
“容器本来是隔离的环境,它们如何才能使用宿主服务器的GPU呢?”
这个问题的答案就是NVIDIA Container Toolkit的架构。
NVIDIA Container Toolkit是一组组件,可帮助在Docker、containerd、CRI-O、LXC等各种容器运行时中使用NVIDIA GPU。NVIDIA官方文档也说明,NVIDIA容器堆栈的设计旨在支持生态系统中的多种容器运行时,而不是仅限于某个特定的运行时。

1. 为什么需要NVIDIA Container Toolkit?
容器本质上是与宿主隔离的执行环境。因此,要在容器内使用GPU,并非简单地运行一个CUDA镜像就能解决。
要使用GPU,大致需要以下要素:
首先,宿主操作系统必须安装NVIDIA GPU驱动。
其次,容器内必须能够访问/dev/nvidia*等GPU设备文件。
第三,容器内必须能够使用NVIDIA驱动相关的库和可执行文件。
第四,Docker、containerd、CRI-O等容器运行时必须理解“此容器需要连接GPU”的信息。
换句话说,GPU容器的运行不仅仅是容器镜像本身的问题。宿主的GPU设备、驱动、库以及容器运行时设置都必须协同工作。
NVIDIA Container Toolkit是一个自动化和标准化此过程的工具。
简而言之,它是这样的:
NVIDIA Container Toolkit是一个连接设备文件、驱动库和运行时设置的层,使容器能够以安全一致的方式使用宿主的NVIDIA GPU。
2. NVIDIA容器堆栈的整体结构
NVIDIA官方文档中描述的NVIDIA容器堆栈主要由三个核心组件组成。
| 组件 | 代表命令/包 | 作用 |
|---|---|---|
| NVIDIA Container Runtime | nvidia-container-runtime | 在Docker/containerd等运行时和runC之间注入NVIDIA配置 |
| NVIDIA Container Runtime Hook | nvidia-container-toolkit, nvidia-container-runtime-hook | 在容器启动前执行GPU设备和库的注入操作 |
| NVIDIA Container Library and CLI | libnvidia-container1, nvidia-container-cli | 处理实际的GPU设备、驱动库和挂载配置 |
这些组件是独立存在的,但普通用户通常安装nvidia-container-toolkit包。NVIDIA文档也说明,在所有使用场景中,仅安装nvidia-container-toolkit包就足够了。
3. 首先理解整体流程
以Docker为例,容器使用GPU的简化流程如下:
사용자
↓
docker run --gpus all ...
↓
Docker daemon
↓
nvidia-container-runtime
↓
runC spec 수정
↓
NVIDIA prestart hook 추가
↓
runC 실행
↓
nvidia-container-cli 호출
↓
GPU 장치와 라이브러리 컨테이너에 주입
↓
컨테이너 내부에서 nvidia-smi 실행 가능

https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/arch-overview.html
这里的核心是,nvidia-container-runtime并非直接完全运行容器的独立运行时,而是在现有runC之前插入NVIDIA相关设置的角色。
根据NVIDIA文档,nvidia-container-runtime过去是runC的一个分支结构,但自2019年以来,它以一个薄包装器的形式运行,封装了宿主上安装的原生runC。这个运行时接收runC spec作为输入,将NVIDIA Container Runtime Hook添加为prestart hook,然后将修改后的spec传递给原生runC。
4. 最底层:libnvidia-container和nvidia-container-cli
NVIDIA容器堆栈中最底层的核心组件是libnvidia-container和nvidia-container-cli。
官方文档解释说,这些组件是用于自动配置GNU/Linux容器以使用NVIDIA GPU的库和CLI,其实现基于Linux内核原语,并设计为不依赖于特定的容器运行时。
简而言之,这一层是实际的工作执行者。
例如,容器内需要连接以下内容:
/dev/nvidia0
/dev/nvidiactl
/dev/nvidia-uvm
NVIDIA driver library
CUDA 관련 runtime library
GPU capabilities 정보
此时,“要放入哪个GPU”、“要挂载哪些库”、“在容器内以什么路径显示”等任务的核心处理工具就是nvidia-container-cli。
也就是说,容器运行时并非直接了解所有NVIDIA GPU的详细配置,而是通过调用NVIDIA提供的nvidia-container-cli来注入GPU支持。
5. 中间层:NVIDIA Container Runtime Hook
下一个重要组件是NVIDIA Container Runtime Hook。
根据官方文档,这个hook是一个实现了runC的prestart hook接口的可执行文件。runC创建容器后,但在容器进程启动之前,会调用此hook。此时,hook会读取容器的config.json信息,并使用适当的标志调用nvidia-container-cli。特别是,将哪个GPU设备注入容器是其中一个重要标志。
更简单地解释一下:
在容器执行过程中,有一个“容器已创建但尚未启动的时刻”。
这个时刻非常重要。
不是在容器已经启动之后强行插入GPU设备和库,而是在容器启动之前预先注入所需的GPU设置。
这就是它被称为“prestart hook”的原因。
컨테이너 생성
↓
아직 애플리케이션 실행 전
↓
NVIDIA prestart hook 실행
↓
GPU 장치와 라이브러리 주입
↓
컨테이너 애플리케이션 시작
由于这种结构,容器内部的应用程序可以像GPU本来就在容器中一样使用它。
6. 上层:NVIDIA Container Runtime
在Docker或containerd环境中,nvidia-container-runtime被配置为OCI兼容运行时。NVIDIA文档也说明,当使用Docker或containerd时,NVIDIA Container Runtime被配置为OCI兼容运行时。
这里的OCI指的是开放容器倡议(Open Container Initiative),这是一个定义容器镜像和运行时行为标准的生态系统。
运行Docker并不意味着Docker独自处理所有事情。Docker内部与containerd、runC等层协同工作。
简化后如下:
Docker CLI
↓
Docker daemon
↓
containerd
↓
OCI runtime
↓
runC
↓
Linux namespace / cgroup 기반 컨테이너 실행
NVIDIA Container Runtime介入到此流程中的OCI运行时阶段。
当用户运行GPU容器时,NVIDIA Container Runtime会修改runC spec,添加NVIDIA hook,然后将实际的容器执行交给原生runC。
理解这种结构可以减少因“nvidia-container-runtime”这个名称可能引起的误解。
nvidia-container-runtime并非替代Docker本身,也不是完全替代runC。在当前结构中,它更像是一个在现有runC之前注入NVIDIA GPU设置的包装器。
7. Docker/containerd与CRI-O/LXC的区别
NVIDIA Container Toolkit的使用流程因容器运行时类型而异。
官方文档说明,对于Docker或containerd,nvidia-container-runtime被配置为OCI兼容运行时。而对于CRI-O和LXC的流程,NVIDIA Container Runtime组件可能不是必需的。
这种差异可以简单总结如下:
| 运行时 | 主要流程 | 特点 |
|---|---|---|
| Docker | Docker → NVIDIA Container Runtime → runC → NVIDIA Hook | 在Docker中注册NVIDIA运行时并使用 |
| containerd | containerd → NVIDIA Container Runtime → runC → NVIDIA Hook | 常用于Kubernetes节点 |
| CRI-O | CRI-O → NVIDIA Hook/CLI层 | 可能不需要单独的NVIDIA Container Runtime |
| LXC | LXC → NVIDIA Hook/CLI层 | 与Docker系列流程不同 |
| Podman | 建议使用CDI | CDI方式近期变得重要 |
也就是说,NVIDIA Container Toolkit不强制采用单一方式。注入GPU的路径会根据容器运行时的结构而变化。
8. 理解软件包结构
NVIDIA Container Toolkit的主要软件包如下:
nvidia-container-toolkit
nvidia-container-toolkit-base
libnvidia-container-tools
libnvidia-container1
软件包依赖关系大致如下:
nvidia-container-toolkit
├─ libnvidia-container-tools
│ └─ libnvidia-container1
└─ nvidia-container-toolkit-base
libnvidia-container-tools
└─ libnvidia-container1
libnvidia-container1
从角色角度看各个软件包如下:
| 软件包 | 作用 |
|---|---|
| libnvidia-container1 | NVIDIA GPU容器支持的核心库 |
| libnvidia-container-tools | 提供nvidia-container-cli等CLI工具 |
| nvidia-container-toolkit-base | 包含nvidia-container-runtime、nvidia-ctk等基本工具 |
| nvidia-container-toolkit | 通常安装的集成软件包 |
在实际操作中,通常不需要逐个安装软件包,大多数情况下安装nvidia-container-toolkit就足够了。

https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/arch-overview.html
官方文档也说明,在所有使用场景中,安装nvidia-container-toolkit就足够了。
9. nvidia-docker2现在是什么?
在旧资料中,您可能会经常看到一个名为nvidia-docker2的软件包。
过去,许多文档都指示用户安装nvidia-docker2才能在Docker中使用NVIDIA GPU。因此,一些旧的博客或安装指南中仍然会出现nvidia-docker2。
然而,当前的NVIDIA官方文档指出,nvidia-docker2和nvidia-container-runtime软件包应被视为已弃用,因为它们的功能已合并到nvidia-container-toolkit软件包中。不过,为了与旧的工作流程兼容,这些软件包可能仍然提供。
总结如下:
과거 방식:
nvidia-docker2 중심
현재 권장 방식:
nvidia-container-toolkit 중심
因此,如果配置新环境,最好以nvidia-container-toolkit和nvidia-ctk为基准,而不是nvidia-docker2。
10. nvidia-ctk是什么工具?
nvidia-ctk是NVIDIA Container Toolkit CLI。
官方文档解释说,这个CLI包含配置Docker等运行时与NVIDIA Container Toolkit一起使用,或生成CDI规范等功能。
例如,要在Docker中配置使用NVIDIA运行时,可以使用以下命令:
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
根据NVIDIA安装文档,此命令会修改宿主的/etc/docker/daemon.json文件,以更新Docker使其能够使用NVIDIA Container Runtime。
在为Kubernetes配置containerd时,可以使用以下命令:
sudo nvidia-ctk runtime configure --runtime=containerd
sudo systemctl restart containerd
根据官方文档,对于containerd,nvidia-ctk通常会创建/etc/containerd/conf.d/99-nvidia.toml的drop-in配置文件,并更新/etc/containerd/config.toml中的imports设置。
也就是说,nvidia-ctk可以被视为一个管理工具,它代替了人们手动打开和复杂修改配置文件的任务。
11. 在Kubernetes中如何理解?
在Kubernetes中使用GPU时,通常需要在节点级别进行以下配置:
GPU가 장착된 노드
↓
NVIDIA GPU Driver 설치
↓
NVIDIA Container Toolkit 설치
↓
containerd 또는 Docker 런타임 구성
↓
NVIDIA Device Plugin 배포
↓
Pod에서 nvidia.com/gpu 리소스 요청
在这里,NVIDIA Container Toolkit是“使容器运行时能够实际将GPU连接到容器的基础层”。
从Kubernetes调度器的角度来看,需要将Pod调度到具有GPU资源的节点上。但是,要使Pod能够在容器内实际使用GPU设备,容器运行时必须能够注入GPU设备和库。
此时就需要NVIDIA Container Toolkit。
例如,在Pod规范中,可以像这样请求GPU资源:
apiVersion: v1
kind: Pod
metadata:
name: gpu-test
spec:
restartPolicy: Never
containers:
- name: cuda
image: nvidia/cuda:12.4.1-base-ubuntu22.04
command: ["nvidia-smi"]
resources:
limits:
nvidia.com/gpu: 1
仅有这个YAML并不能自动启用GPU。
节点上必须安装NVIDIA驱动,容器运行时必须能够通过NVIDIA Container Toolkit注入GPU,并且Kubernetes必须配置Device Plugin才能识别GPU资源。
12. 为什么CDI(Container Device Interface)变得重要?
最近,CDI(Container Device Interface)也变得重要起来。
根据NVIDIA文档,NVIDIA Container Toolkit从v1.12.0开始支持CDI规范的生成。CDI是一个开放规范,旨在抽象化访问NVIDIA GPU等设备的含义,并标准化各种容器运行时中的设备访问方式。
简而言之,CDI是“在容器中表示GPU等设备的标准规范”。
在传统方式中,很大程度上依赖于特定的运行时hook或环境变量。使用CDI,可以以更标准化的方式将GPU设备传递给容器运行时。
特别是在Podman等环境中,NVIDIA建议使用CDI。NVIDIA的安装文档也说明,对于Podman,建议使用CDI进行NVIDIA设备访问。
例如,在Podman中,可以像这样指定CDI设备:
podman run --rm
--device nvidia.com/gpu=all
--security-opt=label=disable
ubuntu nvidia-smi -L
NVIDIA文档说明,此命令应显示与在宿主上运行nvidia-smi -L时相同的GPU列表。
此外,从NVIDIA Container Toolkit v1.18.0开始,一个名为nvidia-cdi-refresh的systemd服务会自动生成和更新CDI规范。此服务在Toolkit安装/升级、GPU驱动安装/升级以及系统重启时创建或更新/var/run/cdi/nvidia.yaml。
13. Docker中GPU容器执行流程示例
假设用户在Docker中执行以下命令:
docker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi
当此命令执行时,内部大致会发生以下事情:
1. 사용자가 Docker CLI로 GPU 사용을 요청한다.
2. Docker daemon이 컨테이너 생성을 준비한다.
3. NVIDIA Container Runtime이 OCI runtime spec을 수정한다.
4. prestart hook에 NVIDIA Container Runtime Hook이 추가된다.
5. runC가 컨테이너 생성 후 시작 직전에 hook을 실행한다.
6. hook이 nvidia-container-cli를 호출한다.
7. nvidia-container-cli가 GPU 장치와 필요한 라이브러리를 컨테이너에 주입한다.
8. 컨테이너 내부에서 nvidia-smi가 GPU를 인식한다.
这种结构中的一个重要点是,它不是将整个GPU驱动安装在容器镜像内部的方式。
它是一种将宿主上安装的NVIDIA驱动和GPU设备连接起来,以便容器可以使用它们的方式。
因此,在GPU容器环境中,以下顺序很重要:
호스트 NVIDIA 드라이버 정상 동작 확인
↓
nvidia-smi 확인
↓
NVIDIA Container Toolkit 설치
↓
Docker/containerd 런타임 설정
↓
GPU 컨테이너 실행 테스트
14. 安装与配置流程
根据NVIDIA Container Toolkit安装文档,首先需要安装适用于Linux发行版的NVIDIA GPU驱动。NVIDIA建议使用发行版的包管理器安装驱动。
在Ubuntu/Debian系列系统中,您需要注册NVIDIA仓库,然后安装Toolkit软件包。官方文档提供了基于apt的安装示例,包括nvidia-container-toolkit、nvidia-container-toolkit-base、libnvidia-container-tools和libnvidia-container1软件包。
安装后,配置Docker的典型流程如下:
# 配置Docker以使用NVIDIA Container Runtime
sudo nvidia-ctk runtime configure --runtime=docker
# 重启Docker
sudo systemctl restart docker
# 测试GPU容器
docker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi
如果在Kubernetes中使用containerd,可以考虑以下流程:
# 配置containerd以使用NVIDIA Container Runtime
sudo nvidia-ctk runtime configure --runtime=containerd
# 重启containerd
sudo systemctl restart containerd
之后,在Kubernetes中,您需要部署NVIDIA Device Plugin,并通过在Pod中请求nvidia.com/gpu资源来运行GPU工作负载。
15. 实践中常见的困惑点
15.1 需要在容器内安装NVIDIA驱动吗?
通常,不建议在容器镜像内部安装宿主专用的NVIDIA驱动。
GPU驱动与宿主内核协同工作。容器被配置为可以使用宿主的GPU设备和驱动库。
容器镜像可以包含CUDA运行时、cuDNN和应用程序代码等,但实际的GPU设备和内核驱动在宿主侧更为重要。
15.2 如果nvidia-smi在宿主上可以运行,但在容器中不行怎么办?
在这种情况下,您需要检查以下内容:
# 检查宿主上GPU识别情况
nvidia-smi
# 检查NVIDIA Container Toolkit是否安装
dpkg -l | grep nvidia-container
# 或者
rpm -qa | grep nvidia-container
# 检查Docker运行时配置
cat /etc/docker/daemon.json
# 检查containerd配置
cat /etc/containerd/config.toml
ls -al /etc/containerd/conf.d/
如果是Docker环境,可以使用以下命令重新应用运行时配置:
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
如果是containerd环境,可以使用以下命令:
sudo nvidia-ctk runtime configure --runtime=containerd
sudo systemctl restart containerd
15.3 需要安装nvidia-docker2吗?
如果是新环境,通常建议以nvidia-container-toolkit为基准,而不是nvidia-docker2。
官方文档说明,nvidia-docker2和nvidia-container-runtime软件包已被弃用,其功能已合并到nvidia-container-toolkit中。
15.4 为什么AWS GPU实例镜像中会安装nvidia-ctk?
AWS的基于GPU的镜像或AI/ML镜像通常会预配置NVIDIA驱动、CUDA和容器执行环境。
如果这些镜像中安装了nvidia-ctk,可以认为其目的是为了方便地配置Docker或containerd,以便在容器中使用GPU。
特别是对于Ollama、vLLM、PyTorch、TensorFlow等工作负载在容器中运行时,GPU设备必须正确地传递给容器。此时,NVIDIA Container Toolkit和nvidia-ctk发挥着重要作用。
16. 一图概览架构
整体结构总结如下:
[사용자 명령]
docker run --gpus all ...
│
▼
[Docker / containerd]
컨테이너 생성 요청 처리
│
▼
[nvidia-container-runtime]
OCI runtime spec 수정
NVIDIA prestart hook 추가
│
▼
[runC]
컨테이너 생성
prestart hook 실행
│
▼
[nvidia-container-runtime-hook]
config.json 분석
nvidia-container-cli 호출
│
▼
[nvidia-container-cli / libnvidia-container]
GPU 장치 파일 주입
드라이버 라이브러리 마운트
환경 구성
│
▼
[컨테이너]
nvidia-smi
CUDA 애플리케이션
AI 모델 추론/학습
理解这个流程可以大大简化GPU容器问题的调试。
例如,当出现问题时,可以像这样分层查看:
1. 호스트 GPU 문제인가?
- nvidia-smi가 호스트에서 동작하는가?
2. Toolkit 설치 문제인가?
- nvidia-container-toolkit 패키지가 설치되어 있는가?
3. 런타임 설정 문제인가?
- Docker/containerd가 NVIDIA runtime을 사용하도록 구성되어 있는가?
4. 컨테이너 실행 옵션 문제인가?
- docker run --gpus all 옵션을 사용했는가?
- Kubernetes Pod에서 nvidia.com/gpu 리소스를 요청했는가?
5. 애플리케이션 문제인가?
- CUDA 버전, 프레임워크 버전, 드라이버 호환성이 맞는가?
17. 结论
NVIDIA Container Toolkit不仅仅是一个“GPU容器执行工具”。
更准确地说,它是一个连接容器运行时和NVIDIA GPU的标准化配置层。
在Docker或containerd中,NVIDIA Container Runtime会进入OCI运行时流程,并通过runC prestart hook调用nvidia-container-cli。对于CRI-O或LXC,流程可能不同,最近通过CDI进行设备标准化也变得重要。
实践中需要记住的核心有三点:
- 首先,GPU驱动必须安装在宿主上。
- 其次,容器运行时必须通过NVIDIA Container Toolkit将GPU设备和库注入容器。
- 第三,在新环境中,最好以nvidia-container-toolkit和nvidia-ctk为中心进行理解和使用,而不是nvidia-docker2。
如果您正在配置AI基础设施、GPU服务器、Kubernetes GPU节点或Ollama/vLLM等LLM推理环境,那么理解NVIDIA Container Toolkit架构是必不可少的基础知识。
了解这种结构后,您就可以更系统地分析“为什么GPU在宿主上可见但在容器中不可见”、“为什么需要修改Docker的daemon.json”、“为什么需要重启containerd”以及“为什么Kubernetes GPU Pod会处于Pending或运行失败状态”等问题。
##
参考资料:
发表回复