AI容器真正使用GPU时,中间并不存在一个简单的“把GPU装进Docker”的过程。容器里的PyTorch、TensorFlow或者CUDA程序最终需要访问服务器上的真实GPU,而GPU又由宿主机Linux内核中的NVIDIA驱动负责管理。
NVIDIA Container Toolkit解决的核心问题,就是把这两套环境连接起来:容器继续保持自己的用户空间和应用依赖,同时能够获得访问宿主机NVIDIA GPU所需要的设备和用户态驱动能力。
理解这个过程,首先要把Docker、CUDA、NVIDIA驱动和Container Toolkit这几个概念分开。
一、GPU驱动实际上在哪里
NVIDIA GPU安装在服务器的PCIe总线上,真正负责管理GPU硬件的内核驱动运行在宿主机Linux内核中。
这意味着Docker镜像通常并不包含一套可以独立控制物理GPU的NVIDIA内核驱动。
一个CUDA容器里面可能已经包含CUDA Runtime、cuDNN、PyTorch或者其他深度学习软件,但GPU内核驱动仍然属于宿主机。
这也是GPU容器与虚拟机的重要区别之一。容器共享宿主机内核,而不是在容器内部运行一个完整的独立Linux内核。
二、NVIDIA Container Toolkit到底是什么
NVIDIA Container Toolkit是一套让容器运行时能够使用NVIDIA GPU的工具和组件。
它并不是CUDA Toolkit,也不是一个新的GPU驱动。
CUDA Toolkit主要面向CUDA开发和运行环境,包括编译器、开发库以及相关工具;NVIDIA Container Toolkit解决的则是“容器怎样获得GPU访问能力”这个问题。
在Docker环境中,Container Toolkit可以与Docker运行时集成。当用户启动一个需要GPU的容器时,运行时根据GPU配置准备相应的设备和用户态组件。
现代部署中通常不应该再把早期的 nvidia-docker-runtime、nvidia-docker2 和CUDA Toolkit混成一个固定的“三组件架构”。
真正重要的是理解容器运行时与NVIDIA Container Toolkit之间的集成关系。
三、容器启动时究竟发生了什么
假设服务器已经正确安装NVIDIA驱动,现在运行一个GPU容器。
用户通过Docker请求GPU资源,例如指定使用某一块GPU。
容器运行时随后根据NVIDIA相关配置准备容器环境。
这个过程可能涉及GPU设备节点、NVIDIA用户态驱动库、CUDA相关能力以及环境变量等资源的配置和注入。
最终,容器中的CUDA应用可以访问由宿主机驱动管理的GPU。
因此可以把整个关系简化成:
AI应用 → CUDA Runtime/用户态库 → NVIDIA驱动接口 → GPU设备 → 物理GPU。
Container Toolkit位于容器运行时和GPU资源之间,负责把容器运行环境正确连接到这条链路。
它并不是自己执行GPU计算,也不是替代NVIDIA驱动。
四、为什么容器里面可以运行nvidia-smi
很多人第一次进入GPU容器时,执行:
nvidia-smi
看到GPU型号、显存使用情况和驱动版本,就会以为“GPU驱动已经装进容器”。
实际上并不是这样理解。
nvidia-smi本身是用户态工具,它通过NVIDIA驱动提供的接口获取GPU状态。
Container Toolkit可以让容器获得运行相关工具和访问GPU所需要的用户态组件以及设备接口,因此容器里的 nvidia-smi 可以与宿主机NVIDIA驱动通信。
真正控制GPU硬件的内核驱动仍然在宿主机。
这也是为什么排查GPU容器问题时,经常需要首先在宿主机执行 nvidia-smi。
如果宿主机本身无法正常识别GPU,那么单纯修改Docker容器配置通常无法解决问题。
五、Container Toolkit不是把GPU显存直接映射给容器
“PCIe把GPU显存映射到容器地址空间”是一个容易产生误解的说法。
容器进程并不是因为Container Toolkit把整块GPU显存当成普通内存映射进进程地址空间,才获得CUDA计算能力。
CUDA程序通过CUDA Runtime和NVIDIA驱动建立GPU执行环境,向GPU提交kernel、管理显存和执行异步操作。
底层的GPU内存管理、命令提交、同步以及硬件控制仍由NVIDIA驱动和GPU硬件负责。
因此,理解GPU容器最重要的一点就是:Container Toolkit提供的是“访问路径和运行时集成”,而不是把物理GPU变成容器自己的虚拟硬件。
六、一个容器能看到几块GPU
GPU容器还涉及资源选择。
假设一台服务器有8块GPU,一个容器可能只需要其中一块。
容器运行时可以根据用户指定的GPU资源限制,把相应GPU设备提供给该容器。
在Docker环境中,--gpus 是常见的GPU资源请求方式。
在Kubernetes环境中,则通常由NVIDIA Device Plugin等组件向Kubernetes注册GPU资源,再根据Pod的资源请求进行设备分配。
这意味着“GPU可见性”和“GPU计算资源隔离”是两个不同问题。
一个容器只能看到指定GPU,并不代表同一块GPU内部已经自动进行了严格的计算资源隔离。
七、多容器共享GPU是另一个问题
如果两个容器同时使用同一块物理GPU,就涉及GPU共享。
这里不能简单认为Container Toolkit会自动把GPU平均切成两半。
不同GPU和不同部署方式可以采用不同的共享机制。
例如支持Multi-Instance GPU(MIG)的GPU可以把物理GPU划分为多个GPU实例。
Time-Slicing则允许多个工作负载交替使用GPU计算资源,但它与严格的硬件级隔离并不是一回事。
MPS又是另一种GPU共享机制。
这些机制分别涉及GPU硬件能力、CUDA以及NVIDIA Kubernetes设备插件等不同层次。Container Toolkit负责让容器获得相应GPU访问能力,但并不是所有GPU资源调度和隔离功能都由它完成。
八、NCCL和Container Toolkit是什么关系
AI训练经常需要多个GPU共同工作。
例如一个分布式训练任务可能需要执行AllReduce,把不同GPU上的梯度进行同步。
NCCL(NVIDIA Collective Communications Library)负责这类GPU集合通信。
Container Toolkit解决的是容器如何访问GPU,而NCCL解决的是GPU之间如何高效通信。
两者可以在同一个容器化AI环境中协同工作,但不能说“Container Toolkit负责AllReduce”。
如果多GPU训练性能很差,需要进一步检查GPU之间的互联拓扑、PCIe、NVLink、NIC、RDMA、NUMA以及NCCL配置。
如果是跨服务器训练,还需要考虑网络带宽和通信路径。
因此,容器网络模式和GPU通信性能也不能简单画等号。
九、Docker bridge网络不会让GPU计算经过网络
原文中把Docker bridge网络和GPU驱动性能直接联系起来,这是需要纠正的。
普通单机CUDA计算并不会因为容器使用bridge网络,就把GPU计算数据通过宿主机网络接口传输。
GPU访问主要发生在容器进程、用户态CUDA库、宿主机GPU驱动和GPU硬件之间。
只有当AI应用本身需要进行跨容器或跨服务器网络通信时,容器网络才成为相关因素。
例如分布式训练的GPU之间需要跨服务器交换数据,此时网络接口、RDMA、交换机和NIC性能才会成为重要瓶颈。
使用host network还是bridge network,需要根据应用的网络需求、安全要求和部署架构决定,而不能简单说host network能够“直接访问GPU驱动”。
十、GPU性能监控不能只看nvidia-smi
nvidia-smi非常有用,可以查看GPU利用率、显存使用、温度、功耗以及部分运行状态。
但是GPU利用率高,并不代表GPU一定计算效率高;GPU利用率低,也不一定意味着GPU本身性能不足。
例如AI推理可能受到CPU预处理、数据加载、PCIe传输、显存带宽、kernel launch、同步等待或者模型本身计算结构影响。
因此性能分析通常需要结合应用层指标和更专业的profiling工具。
对于训练任务,可以进一步观察tokens/s、samples/s、GPU利用率、显存使用、通信时间以及数据加载等待时间。
对于推理服务,还应该观察batch size、请求延迟、吞吐量和GPU利用率之间的关系。
如果怀疑显存带宽成为瓶颈,也应该通过性能分析工具确认,而不是仅仅看到显存占用较高就下结论。
十一、为什么GPU容器仍然需要宿主机驱动管理
GPU容器虽然把大量软件环境固定进镜像,却无法把物理GPU和宿主机内核一起封装进去。
因此一个CUDA容器能够正常运行,通常需要满足几个条件:
宿主机正确安装并加载NVIDIA驱动;
GPU硬件能够被宿主机识别;
容器运行时正确安装和配置NVIDIA Container Toolkit;
容器中的CUDA Runtime与宿主机驱动满足兼容要求;
应用框架能够支持目标GPU架构。
这也解释了一个很常见的现象:同一个Docker镜像在服务器A能够运行,在服务器B却启动失败。
如果镜像完全相同,问题未必出在容器本身,也可能是服务器B的GPU型号、NVIDIA驱动、运行时配置或者硬件环境不同。
十二、真正理解GPU容器应该看完整链路
把整个架构放在一起,可以得到一个更加清晰的关系:
物理GPU由宿主机硬件和NVIDIA内核驱动负责控制。
Docker负责容器生命周期和用户空间隔离。
NVIDIA Container Toolkit负责让容器运行时正确获得NVIDIA GPU访问能力。
容器镜像提供CUDA Runtime、深度学习框架、应用程序以及其他用户空间依赖。
CUDA负责应用程序与GPU计算环境之间的编程接口。
Kubernetes等编排系统负责更大规模环境中的资源调度,而NVIDIA Device Plugin负责把GPU资源接入Kubernetes设备插件机制。
NCCL则负责多GPU和分布式GPU集合通信。
每一层解决的问题不同。
因此,NVIDIA Container Toolkit最重要的价值并不是“把GPU虚拟化”,而是把原本属于宿主机的GPU能力,以容器运行时能够理解和管理的方式提供给容器。
这也是GPU容器能够同时保持软件环境一致性和硬件加速能力的关键。
对于AI基础设施来说,真正成熟的GPU容器架构不是简单地让 nvidia-smi 在容器里显示出一张GPU,而是建立一条从物理硬件、宿主机驱动、容器运行时、CUDA用户态环境,到AI框架和应用程序的完整兼容链。
一旦把这条链理解清楚,很多所谓“CUDA容器突然不能用GPU”“PyTorch找不到CUDA”“多GPU训练速度异常”或者“两个容器抢同一张GPU”的问题,就可以分别定位到驱动、运行时、用户态库、设备分配、GPU共享或者通信拓扑,而不必把所有故障都归结为Docker本身。
NVIDIA Container Toolkit 在 AI 容器中的作用是什么,从容器到 GPU 驱动完整解释
图片说明:示意图 图片来源:Public Domain(公有领域)
喜欢这篇报道?
使用下面的功能,方便以后继续阅读和分享 MNewsTV
关于文章收藏
收藏不需要注册帐号,收藏信息仅保存在当前浏览器中。
删除收藏请进入「我的收藏」进行管理。
捐助(Paypal): https://www.paypal.me/observeccp 订阅中国观察电报 Telegram : https://t.me/s/ObserveCCP