<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>Jimmy Song – GPU 软件栈与容器化</title><link>https://jimmysong.io/zh/book/gpu-infra/software-stack/</link><description>Recent content in GPU 软件栈与容器化 on Jimmy Song</description><generator>Hugo -- gohugo.io</generator><language>zh</language><managingEditor>Jimmy Song</managingEditor><webMaster>Jimmy Song</webMaster><follow_challenge><feedId>51621818828612637</feedId><userId>59800919738273792</userId></follow_challenge><lastBuildDate>Sun, 30 Aug 2026 00:00:00 +0800</lastBuildDate><atom:link href="https://jimmysong.io/zh/book/gpu-infra/software-stack/index.xml" rel="self" type="application/rss+xml"/><item><title>NVIDIA 软件栈：一个应用，多份契约</title><link>https://jimmysong.io/zh/book/gpu-infra/software-stack/nvidia-software-stack/</link><pubDate>Mon, 31 Aug 2026 02:47:53 +0000</pubDate><author>Jimmy Song</author><guid>https://jimmysong.io/zh/book/gpu-infra/software-stack/nvidia-software-stack/</guid><description>从固件到 TensorRT，GPU 应用坐在一张由契约组成的分层图上：应用调库、库调 CUDA、运行时找驱动、驱动管硬件。逐层拆解每层的职责与故障信号，理解驱动与运行时的兼容性方向。</description><content:encoded>
&lt;blockquote&gt;
&lt;p&gt;GPU 容器不会直接和硅片对话。任何一条边界上的失配，都可能表现为“莫名其妙的应用错误”。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure class="mx-auto text-center"&gt;
&lt;img src="https://assets.jimmysong.io/images/book/gpu-infra/software-stack/nvidia-software-stack/software-stack-layers.svg" data-img="https://assets.jimmysong.io/images/book/gpu-infra/software-stack/nvidia-software-stack/software-stack-layers.svg" alt="图 1: NVIDIA 软件栈的分层契约" data-caption="图 1: NVIDIA 软件栈的分层契约"
width="1719"
height="1203"
loading="lazy" decoding="async" class="image-loading"
onload="this.classList.remove('image-loading'); this.classList.add('image-loaded');"
onerror="handleImageError(this); this.classList.remove('image-loading');"&gt;
&lt;figcaption&gt;图 1: NVIDIA 软件栈的分层契约&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;应用或框架调用库；库调用 CUDA；CUDA 运行时与驱动交互；容器运行时注入设备访问；内核驱动与硬件对话。排查 GPU 问题的第一课，是先判断故障发生在哪一层，自底向上检查往往最快。&lt;/p&gt;
&lt;h2 id="逐层拆解"&gt;逐层拆解&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;层&lt;/th&gt;
&lt;th&gt;职责&lt;/th&gt;
&lt;th&gt;故障信号&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;固件 / GPU&lt;/td&gt;
&lt;td&gt;供电、内存、引擎、链路、RAS&lt;/td&gt;
&lt;td&gt;硬件错误、复位、链路故障&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;内核驱动&lt;/td&gt;
&lt;td&gt;特权设备访问与内存管理&lt;/td&gt;
&lt;td&gt;模块失配、Xid、设备消失&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Container Toolkit&lt;/td&gt;
&lt;td&gt;向容器注入设备与库&lt;/td&gt;
&lt;td&gt;容器里没有 GPU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CUDA 运行时&lt;/td&gt;
&lt;td&gt;kernel 启动、流、内存、事件、驱动 API&lt;/td&gt;
&lt;td&gt;符号缺失或运行时不匹配&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cuBLAS / cuDNN&lt;/td&gt;
&lt;td&gt;优化的线性代数与神经网络原语&lt;/td&gt;
&lt;td&gt;不支持的路径或糟糕的 kernel 选择&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NCCL&lt;/td&gt;
&lt;td&gt;集合与对等通信&lt;/td&gt;
&lt;td&gt;挂起、超时、扩展缓慢&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TensorRT / TRT-LLM&lt;/td&gt;
&lt;td&gt;优化的推理图与引擎执行&lt;/td&gt;
&lt;td&gt;构建失配或不支持的算子&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DCGM&lt;/td&gt;
&lt;td&gt;遥测、诊断、健康、exporter 集成&lt;/td&gt;
&lt;td&gt;指标或健康状态缺失&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;figcaption class="text-center mb-3"&gt;
表 1: NVIDIA 软件栈逐层职责与故障信号
&lt;/figcaption&gt;
&lt;p&gt;每一层的故障签名都不同：Xid 错误指向驱动与硬件层（见&lt;a href="../../observability/gpu-metrics-semantics/"&gt;指标语义&lt;/a&gt;），“容器里没有 GPU”指向工具链层（见下一章），符号缺失指向运行时版本失配，扩展缓慢则多半是 NCCL 与互连问题（见&lt;a href="../../fundamentals/gpu-interconnect-collectives/"&gt;互连与集合通信&lt;/a&gt;）。&lt;/p&gt;
&lt;h2 id="驱动与运行时兼容性的方向"&gt;驱动与运行时：兼容性的方向&lt;/h2&gt;
&lt;p&gt;主机驱动是特权的，与内核和 GPU 绑定。容器通常携带用户态运行时部件和应用库。&lt;strong&gt;驱动必须支持运行时与 GPU 架构&lt;/strong&gt;；基于较新 CUDA 版本构建的镜像，可能在驱动较旧的节点上失败。更新的驱动并不保证所有应用都兼容，但过旧的驱动是常见的头号嫌疑。&lt;/p&gt;
&lt;div class="alert alert-note-container"&gt;
&lt;div class="alert-note-title px-2"&gt;
工程纪律
&lt;/div&gt;
&lt;div class="alert-note px-2"&gt;
锁定节点驱动、基础镜像、框架和 GPU Operator 版本，建立兼容性矩阵。在改动整个机群之前，用诊断镜像加一个代表性工作负载测试升级。
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="cuda-库与优化路径"&gt;CUDA 库与优化路径&lt;/h2&gt;
&lt;p&gt;cuBLAS 加速稠密线性代数；cuDNN 提供优化的深度学习原语；NCCL 处理分布式通信；TensorRT 构建优化的推理引擎；TensorRT-LLM 把这些思想专门化用于语言模型服务；DCGM 及其 exporter 暴露健康与遥测；CUDA Toolkit 提供把各层粘合在一起的编译器、运行时、工具和编程接口。&lt;/p&gt;
&lt;p&gt;应用很少直接使用所有这些库，但性能与可靠性正是从它们的&lt;strong&gt;组合&lt;/strong&gt;中涌现，这也是为什么版本矩阵管理（详见&lt;a href="../../production/security-lifecycle/"&gt;安全、可靠性与生命周期&lt;/a&gt;）是平台团队的核心职责。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;把 GPU 栈看成一张契约图，“哪层 owns 这个故障”就有了判定依据。本章的分层表也是全书排障章节的索引：固件与驱动问题走 Xid 路径，工具链问题走 Toolkit 路径，性能问题走互连与调度路径。下一章深入其中的 Container Toolkit 层。&lt;/p&gt;</content:encoded></item><item><title>Kubernetes 的出身：从 Borg 到 GPU 事实编排器</title><link>https://jimmysong.io/zh/book/gpu-infra/software-stack/kubernetes-origin/</link><pubDate>Sun, 30 Aug 2026 00:00:00 +0000</pubDate><author>Jimmy Song</author><guid>https://jimmysong.io/zh/book/gpu-infra/software-stack/kubernetes-origin/</guid><description>Kubernetes 如何从 Google Borg 的内部经验走向开源事实标准，又为什么在容器与 AI 推理爆炸之后成为 GPU 工作负载的默认编排器：一段编年时间线加三个关键洞察。</description><content:encoded>
&lt;blockquote&gt;
&lt;p&gt;Kubernetes 原本为无状态微服务而生；它成为 GPU 编排器，不是因为设计初衷，而是因为它无处不在、可扩展，而推理时代的所有需求它都已经具备。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="kubernetes-之前的世界"&gt;Kubernetes 之前的世界&lt;/h2&gt;
&lt;p&gt;在 Kubernetes 出现之前，部署分布式应用意味着两个痛苦选择之一：用手工部署脚本管理裸机服务器，或用 Chef、Puppet、Ansible 之类的工具管理虚拟机。扩容意味着手工开通新虚机；故障转移依赖自定义脚本；环境一致性是神话，生产环境“在我机器上是好的”问题就是日常。&lt;/p&gt;
&lt;p&gt;2013 年，Solomon Hykes 在 PyCon 上做了五分钟的闪电演讲，改变了一切：他演示了一个即将发布的工具 Docker。Docker 用干净的 API 包装了底层命名空间与 cgroups 的复杂性，把 Linux 容器带入主流。突然之间，你可以把应用及其全部依赖打包成一个可移植、可复现的镜像。容器革命开始了。&lt;/p&gt;
&lt;p&gt;但容器带来了新问题：现在你有几百个容器分布在几十台主机上，全都需要被启动、停止、扩缩、更新和健康检查。编排（orchestration）成了必需品。&lt;/p&gt;
&lt;h2 id="诞生于-google-的-borg"&gt;诞生于 Google 的 Borg&lt;/h2&gt;
&lt;p&gt;Google 从 2003 年起就在内部以一套叫 Borg 的集群管理系统大规模运行容器化工作负载。Docker 时代到来时，Google 工程师 Joe Beda、Brendan Burns 和 Craig McLuckie 看到了把 Borg 的经验带进开源世界的机会。这个内部项目的代号是 Project 7，致敬《星际迷航》中脱离了 Borg 集合的角色“九之七”（Seven of Nine），Kubernetes 标志上的七根辐条正源于此。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;时间&lt;/th&gt;
&lt;th&gt;里程碑&lt;/th&gt;
&lt;th&gt;发生了什么&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2014 年 6 月&lt;/td&gt;
&lt;td&gt;首次 GitHub 提交&lt;/td&gt;
&lt;td&gt;Google 在 DockerCon 上发布 Kubernetes，Eric Brewer 的主题演讲把 K8s 带给世界&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2015 年 7 月&lt;/td&gt;
&lt;td&gt;K8s v1.0：生产就绪&lt;/td&gt;
&lt;td&gt;Kubernetes 1.0 发布。Google 联合 Linux 基金会成立 CNCF，K8s 作为首个种子项目捐出&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2015–16&lt;/td&gt;
&lt;td&gt;CNCF 与生态成长&lt;/td&gt;
&lt;td&gt;Microsoft、Red Hat、IBM 加入；面向有状态应用的 StatefulSets；包管理器 Helm 诞生&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2017&lt;/td&gt;
&lt;td&gt;K8s 1.8：RBAC + 设备插件&lt;/td&gt;
&lt;td&gt;基于角色的访问控制 GA；关键：设备插件框架以 1.8 alpha 引入，GPU 从此可以暴露给 K8s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2018&lt;/td&gt;
&lt;td&gt;K8s 1.10：设备插件稳定&lt;/td&gt;
&lt;td&gt;设备插件框架进入 beta；CRI-O 运行时；CoreDNS 成为默认；GKE/EKS/AKS 上线&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2019–20&lt;/td&gt;
&lt;td&gt;K8s 成为中坚&lt;/td&gt;
&lt;td&gt;91% 的组织在运行容器；K8s 用于微服务、数据库、ML 工作负载、网络功能&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2020–22&lt;/td&gt;
&lt;td&gt;AI 工作负载规模化&lt;/td&gt;
&lt;td&gt;GPT-3、BERT、Stable Diffusion 全部在 GPU 集群上训练；GPU Operator v1.0 发布&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022&lt;/td&gt;
&lt;td&gt;ChatGPT 改变一切&lt;/td&gt;
&lt;td&gt;GPU 需求爆炸，每个组织都需要 GPU 基础设施，而 Kubernetes 正是它们的运行方式&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2024–26&lt;/td&gt;
&lt;td&gt;DRA 时代开启&lt;/td&gt;
&lt;td&gt;K8s 1.32（DRA beta）、1.34（DRA GA）；NVIDIA 向 CNCF 捐赠 DRA Driver 并成为白金会员&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;figcaption class="text-center mb-3"&gt;
表 1: Kubernetes 与 GPU 编排的关键时间线
&lt;/figcaption&gt;
&lt;p&gt;注意 2017 年这一行：设备插件框架（详见&lt;a href="../../fundamentals/k8s-device-model/"&gt;设备资源抽象&lt;/a&gt;）与 GPU 的结缘从 K8s 1.8 就开始了，此后近十年 GPU 接入 Kubernetes 的方式都围绕它展开，直到 DRA 登场。&lt;/p&gt;
&lt;h2 id="为什么-kubernetes-成了-gpu-编排器"&gt;为什么 Kubernetes 成了 GPU 编排器&lt;/h2&gt;
&lt;p&gt;下面这个关键洞察解释了为什么原本为无状态微服务构建的 Kubernetes，成了 GPU 工作负载的事实编排器：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;无处不在：&lt;/strong&gt; 到 2020 年，Kubernetes 已经运行在每个主要数据中心里。团队熟悉它、工具链存在、云厂商提供托管版本。另建一套 GPU 调度系统，意味着重建 Kubernetes 已有的一切：网络、RBAC、服务发现、存储集成。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可扩展性：&lt;/strong&gt; K8s 生来为扩展而设计：自定义资源定义（CRD）、准入 Webhook、设备插件、Operator 模式。NVIDIA 无需 fork Kubernetes 就能接入 GPU 支持。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI 接理爆炸：&lt;/strong&gt; 训练一个模型与大规模服务它有不同的需求。推理需要弹性伸缩、多租户、负载均衡、滚动更新，这些 Kubernetes 都已具备。在 Kubernetes 之外做推理，意味着把这一切重建一遍。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="alert alert-note-container"&gt;
&lt;div class="alert-note-title px-2"&gt;
历史的必然路径
&lt;/div&gt;
&lt;div class="alert-note px-2"&gt;
ChatGPT 上线的那一刻，每一家大公司都想要 GPU 基础设施。它们已经有了 Kubernetes。阻力最小的路径是：扩展 Kubernetes 以支持 GPU。NVIDIA 构建的正是这个。
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;Kubernetes 的胜利不是功能清单的胜利，而是生态位的选择：它在正确的时间（容器标准化）、以正确的架构（可扩展控制面）占据了编排层，使 GPU 支持可以被“插入”而非“重造”。理解这段历史，就能理解为什么后续章节中的设备插件、GPU Operator 与 DRA 都以“扩展 Kubernetes”而非“绕开 Kubernetes”的方式演化。&lt;/p&gt;</content:encoded></item><item><title>容器与 GPU 的问题：为什么不能开箱即用</title><link>https://jimmysong.io/zh/book/gpu-infra/software-stack/container-gpu-problem/</link><pubDate>Sun, 30 Aug 2026 00:00:00 +0000</pubDate><author>Jimmy Song</author><guid>https://jimmysong.io/zh/book/gpu-infra/software-stack/container-gpu-problem/</guid><description>容器只是命名空间与 cgroups，而 GPU 由专有内核模块与用户态驱动库组成，标准容器拿不到设备文件也拿不到库。从 nvidia-docker v1 到 v2 的 OCI 钩子方案，看这道缝最初是如何缝合的。</description><content:encoded>
&lt;blockquote&gt;
&lt;p&gt;GPU 无法在容器里“开箱即用”不是缺陷，而是架构使然：容器是内核特性的组合，而 GPU 恰恰不是内核原生资源。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="容器究竟如何工作"&gt;容器究竟如何工作&lt;/h2&gt;
&lt;p&gt;容器不是轻量级虚拟机。它是一组 Linux 内核特性的集合（主要是命名空间 namespace 与 cgroups，前者负责进程、网络、文件系统、用户隔离，后者负责资源记账与限制），让一个进程相信自己独占整台机器。&lt;/p&gt;
&lt;p&gt;当你运行 &lt;code&gt;docker run nginx&lt;/code&gt; 时，容器运行时（Docker → containerd → runc）为进程创建隔离的命名空间、挂载容器镜像文件系统、配置网络，并对 CPU 和内存施加 cgroup 限制。这一切都是纯 Linux 内核，除了内核本来就管理的东西，没有任何硬件驱动的参与。&lt;/p&gt;
&lt;p&gt;这正是容器启动快、重量轻的原因：它们共享主机内核，没有虚拟机管理器开销。但这个设计在加入 GPU 时制造了一个棘手问题。&lt;/p&gt;
&lt;h2 id="根本问题gpu-不是内核原生资源"&gt;根本问题：GPU 不是内核原生资源&lt;/h2&gt;
&lt;p&gt;与 CPU 核和系统内存不同（Linux 内核通过进程调度和虚拟内存系统原生管理它们），GPU 由 GPU 厂商加载的专有内核模块管理。对 NVIDIA 来说，就是 &lt;code&gt;nvidia.ko&lt;/code&gt; 内核模块及其上的用户态驱动栈。&lt;/p&gt;
&lt;p&gt;GPU 通过一组设备文件向用户态暴露自己。在只有一块 NVIDIA GPU 的节点上，你会发现：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Device files created by the NVIDIA kernel module&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/dev/nvidia0 &lt;span class="c1"&gt;# GPU 本体&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/dev/nvidiactl &lt;span class="c1"&gt;# GPU 控制设备（所有 GPU 共享）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/dev/nvidia-uvm &lt;span class="c1"&gt;# 统一虚拟内存（UVM）驱动&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/dev/nvidia-uvm-tools &lt;span class="c1"&gt;# UVM 调试工具&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/dev/nvidia-modeset &lt;span class="c1"&gt;# 显示模式设置（可选）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 同时：必须存在于容器中的 NVIDIA 库&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/usr/lib/x86_64-linux-gnu/libcuda.so.1 &lt;span class="c1"&gt;# CUDA 运行时&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/usr/lib/x86_64-linux-gnu/libnvidia-ml.so.1 &lt;span class="c1"&gt;# NVML（管理接口）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/usr/lib/x86_64-linux-gnu/libnvidia-glcore.so &lt;span class="c1"&gt;# GL 加速&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;问题就在这里：一个标准容器得不到其中任何一项。容器文件系统与主机隔离，设备文件在容器里不存在，NVIDIA 驱动库也没有被挂载。即使你在容器镜像里装了 CUDA，运行时它也无处可谈。&lt;/p&gt;
&lt;div class="alert alert-warning-container"&gt;
&lt;div class="alert-warning-title px-2"&gt;
天真的失败
&lt;/div&gt;
&lt;div class="alert-warning px-2"&gt;
不做 GPU 配置直接运行 &lt;code&gt;docker run my-cuda-app&lt;/code&gt;，结果是：&lt;code&gt;CUDA error: no kernel image is available for execution on the device&lt;/code&gt;，或者干脆 &lt;code&gt;nvidia-smi: command not found&lt;/code&gt;，更糟的是：进程正常启动但&lt;strong&gt;悄悄回落到 CPU&lt;/strong&gt;。没有报错，只是推理慢了 100 倍。
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="早期尝试nvidia-docker-v12016"&gt;早期尝试：nvidia-docker v1（2016）&lt;/h2&gt;
&lt;p&gt;2016 年 NVIDIA 发布 DGX-1（世界上第一台“盒子里的 AI 超算”），随机器附带了 NVIDIA Docker，一个改造过的 Docker CLI 包装器。nvidia-docker v1 的做法是维护一个单独的 Docker 卷插件，把 GPU 库和设备文件打包进去，启动时再挂载到容器里。&lt;/p&gt;
&lt;p&gt;这能用，但问题很深：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;它要求一条单独的 &lt;code&gt;nvidia-docker&lt;/code&gt; 命令，破坏了标准 Docker 工作流和 CI/CD 流水线&lt;/li&gt;
&lt;li&gt;卷里和主机上的驱动版本必须完全一致，维护起来是噩梦&lt;/li&gt;
&lt;li&gt;它无法与 Kubernetes、Docker Swarm 或任何绕过 Docker CLI 的编排器配合&lt;/li&gt;
&lt;li&gt;每次 nvidia-docker 升级都要重建卷插件，每逢内核或驱动更新都极其脆弱&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI 社区在快速膨胀，这个 hack 走不远。&lt;/p&gt;
&lt;h2 id="nvidia-docker-v2oci-钩子方案2017"&gt;nvidia-docker v2：OCI 钩子方案（2017）&lt;/h2&gt;
&lt;p&gt;2017 年，NVIDIA 推倒重来。nvidia-docker v2 不再包装 Docker CLI，而是引入了自定义 OCI 运行时的概念，在最底层钩进容器创建过程本身。&lt;/p&gt;
&lt;p&gt;关键洞察是：开放容器倡议（Open Container Initiative，OCI）运行时规范定义了容器如何被创建。参考实现 runc 遵循该规范。规范允许&lt;strong&gt;预启动钩子（pre-start hook）&lt;/strong&gt;：在容器创建之后、启动之前运行的可执行文件。NVIDIA 正是利用这个钩子点把 GPU 访问注入容器。&lt;/p&gt;
&lt;div class="alert alert-note-container"&gt;
&lt;div class="alert-note-title px-2"&gt;
架构转变
&lt;/div&gt;
&lt;div class="alert-note px-2"&gt;
NVIDIA 没有修改 Docker，而是在 runc 外面包了一层薄壳，把 GPU 资源作为预启动钩子注入。Docker 调用这个包装器（&lt;code&gt;nvidia-container-runtime&lt;/code&gt;）的方式与调用 runc 完全一样。Docker 无需任何改动；containerd、CRI-O 及任何兼容 OCI 的运行时同理。
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;这一钩子机制后来被标准化为 CDI（容器设备接口），并成为 &lt;a href="../../data-plane/dra/"&gt;DRA 路径&lt;/a&gt;的注入基础，从 v2 到 CDI 再到 DRA 一脉相承。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;容器与 GPU 的缝隙本质上是&lt;strong&gt;两套世界的接口失配&lt;/strong&gt;：容器世界只认识内核原生资源，GPU 世界由厂商内核模块和用户态库构成。nvidia-docker v2 用 OCI 预启动钩子在进程创建的最底层缝合了这道缝，其思想延续至今。下一章将拆解完成这件事的完整工具链。&lt;/p&gt;</content:encoded></item><item><title>NVIDIA Container Toolkit：四个组件与 CDI 深度解析</title><link>https://jimmysong.io/zh/book/gpu-infra/software-stack/nvidia-container-toolkit/</link><pubDate>Sun, 30 Aug 2026 00:00:00 +0000</pubDate><author>Jimmy Song</author><guid>https://jimmysong.io/zh/book/gpu-infra/software-stack/nvidia-container-toolkit/</guid><description>libnvidia-container、OCI 运行时钩子、nvidia-container-runtime 与 nvidia-ctk 各自做什么、如何协作；CDI 如何把厂商钩子变成中立标准；附驱动安装、工具包安装、运行时配置与验证的完整命令，以及关键 NVIDIA 基础镜像选型。</description><content:encoded>
&lt;blockquote&gt;
&lt;p&gt;NVIDIA Container Toolkit（NCT）是其他一切的地基：设备插件宣告的资源、GPU Operator 部署的组件，最终都靠它把 GPU 真正放进容器。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="什么是-nvidia-container-toolkit"&gt;什么是 NVIDIA Container Toolkit&lt;/h2&gt;
&lt;p&gt;NVIDIA Container Toolkit（NCT）是一组软件组件的集合，让 NVIDIA GPU 在所有主流容器运行时（Docker、containerd、CRI-O 和 Podman）中都可用。它由四个各司其职的组件组成。理解每一个都至关重要，因为 GPU 容器出问题的时候（它们一定会出问题），你需要确切知道故障发生在哪一层。&lt;/p&gt;
&lt;h2 id="组件一libnvidia-container"&gt;组件一：libnvidia-container&lt;/h2&gt;
&lt;p&gt;libnvidia-container 是最底层的组件：一个 C 库和 CLI 工具，执行向容器注入 GPU 的实际动作。被调用时，它做以下事情：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;读取容器的 cgroup 和进程命名空间&lt;/li&gt;
&lt;li&gt;通过 NVML（NVIDIA 管理库）发现主机上的全部 NVIDIA GPU 设备&lt;/li&gt;
&lt;li&gt;把所需的 GPU 设备文件（&lt;code&gt;/dev/nvidia*&lt;/code&gt;）绑定挂载进容器的 &lt;code&gt;/dev&lt;/code&gt; 命名空间&lt;/li&gt;
&lt;li&gt;把主机上的 NVIDIA 驱动用户态库（&lt;code&gt;libcuda.so&lt;/code&gt;、&lt;code&gt;libnvidia-ml.so&lt;/code&gt; 等）绑定挂载进容器的库路径&lt;/li&gt;
&lt;li&gt;注入必要的环境变量（如 &lt;code&gt;NVIDIA_VISIBLE_DEVICES&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;可选地配置统一虚拟内存（UVM）与管理文件&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="alert alert-note-container"&gt;
&lt;div class="alert-note-title px-2"&gt;
为什么挂载主机库而不是打包进镜像
&lt;/div&gt;
&lt;div class="alert-note px-2"&gt;
CUDA 用户态库必须与内核驱动版本精确匹配。如果把库烧进镜像，主机上每次驱动更新都会弄坏所有容器。运行时从主机挂载，库就永远与正在运行的驱动匹配，无需重建镜像。
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# nvidia-container-cli（libnvidia-container 的 CLI 包装，很少直接调用）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nvidia-container-cli --load-kmods configure &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --ldconfig&lt;span class="o"&gt;=&lt;/span&gt;@/sbin/ldconfig &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --require&lt;span class="o"&gt;=&lt;/span&gt;cuda&amp;gt;&lt;span class="o"&gt;=&lt;/span&gt;12.0 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --pid&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;PID&amp;gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --device&lt;span class="o"&gt;=&lt;/span&gt;all
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 查看工具包可见的 GPU&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nvidia-container-cli info
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nvidia-container-cli list&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="组件二nvidia-container-runtime-hook"&gt;组件二：NVIDIA Container Runtime Hook&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;nvidia-container-runtime-hook&lt;/code&gt;（同样以 &lt;code&gt;nvidia-container-toolkit&lt;/code&gt; 包发布）是 OCI 预启动钩子可执行文件，是 OCI 规范与 libnvidia-container 之间的粘合剂。执行流程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;runc 创建容器（命名空间、cgroups、文件系统），但尚未启动进程&lt;/li&gt;
&lt;li&gt;runc 读取 OCI 规范的 &lt;code&gt;hooks.prestart&lt;/code&gt; 数组，找到 NVIDIA 钩子&lt;/li&gt;
&lt;li&gt;runc 携带容器的 &lt;code&gt;config.json&lt;/code&gt; 和进程 ID 执行钩子&lt;/li&gt;
&lt;li&gt;钩子从容器环境读取 &lt;code&gt;NVIDIA_VISIBLE_DEVICES&lt;/code&gt; 和 &lt;code&gt;NVIDIA_DRIVER_CAPABILITIES&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;钩子调用 &lt;code&gt;nvidia-container-cli configure&lt;/code&gt;，后者执行 libnvidia-container 注入 GPU 设备与库&lt;/li&gt;
&lt;li&gt;钩子退出，runc 启动容器进程，容器现在拥有 GPU 访问&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 控制 GPU 可见性与能力的环境变量&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;NVIDIA_VISIBLE_DEVICES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;all &lt;span class="c1"&gt;# 所有 GPU&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;NVIDIA_VISIBLE_DEVICES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0,1 &lt;span class="c1"&gt;# 仅 GPU 0 和 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;NVIDIA_VISIBLE_DEVICES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;none &lt;span class="c1"&gt;# 无 GPU（纯 CPU 容器）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;NVIDIA_DRIVER_CAPABILITIES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;compute,utility &lt;span class="c1"&gt;# 最常用&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;NVIDIA_DRIVER_CAPABILITIES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;all &lt;span class="c1"&gt;# 全部（含显示）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;NVIDIA_DRIVER_CAPABILITIES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;compute,compat32 &lt;span class="c1"&gt;# 32 位 CUDA 兼容&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;NVIDIA_REQUIRE_CUDA&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cuda&amp;gt;&lt;span class="o"&gt;=&lt;/span&gt;12.0 &lt;span class="c1"&gt;# 驱动 CUDA &amp;lt; 12.0 则失败&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;设备插件（见&lt;a href="../../fundamentals/k8s-device-model/"&gt;设备资源抽象&lt;/a&gt;）在 &lt;code&gt;Allocate&lt;/code&gt; 阶段设置的正是 &lt;code&gt;NVIDIA_VISIBLE_DEVICES&lt;/code&gt;，两条链路在这里汇合。&lt;/p&gt;
&lt;h2 id="组件三nvidia-container-runtime"&gt;组件三：NVIDIA Container Runtime&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;nvidia-container-runtime&lt;/code&gt; 是一个兼容 OCI 的运行时包装器，位于 Docker/containerd 与真正的 runc 之间，唯一职责是在把 OCI 规范传给 runc 之前注入 NVIDIA 钩子。自 2019 年起它实现为一层薄垫片：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 配置 nvidia-container-runtime 后 Docker 的执行流：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Docker（守护进程）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;→ 调用 nvidia-container-runtime（而非 runc）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;→ nvidia-container-runtime 读取 OCI config.json
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;→ 注入预启动钩子：nvidia-container-runtime-hook
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;→ 把修改后的 config.json 交给 runc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;→ runc 创建容器
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;→ runc 执行预启动钩子（nvidia-container-runtime-hook）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;→ 钩子调用 libnvidia-container → GPU 设备注入完成
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;→ runc 启动容器进程
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;→ GPU 可用！&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;对 CRI-O（用于 OpenShift 和许多生产 K8s 集群）来说，这个包装器并非必需，CRI-O 原生支持 OCI 钩子，可直接调用钩子。&lt;/p&gt;
&lt;h2 id="组件四nvidia-ctk-cli"&gt;组件四：nvidia-ctk CLI&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;nvidia-ctk&lt;/code&gt; 是工具包的管理接口，负责容器运行时配置、CDI 规范生成和诊断：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 配置 containerd 使用 nvidia-container-runtime&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nvidia-ctk runtime configure --runtime&lt;span class="o"&gt;=&lt;/span&gt;containerd
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 配置 Docker / CRI-O&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nvidia-ctk runtime configure --runtime&lt;span class="o"&gt;=&lt;/span&gt;docker
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nvidia-ctk runtime configure --runtime&lt;span class="o"&gt;=&lt;/span&gt;crio
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 生成 CDI 规范（现代方式）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nvidia-ctk cdi generate --output&lt;span class="o"&gt;=&lt;/span&gt;/etc/cdi/nvidia.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 列出 CDI 设备 / 验证安装&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nvidia-ctk cdi list
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nvidia-ctk --version&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="cdi容器设备接口现代路径"&gt;CDI：容器设备接口（现代路径）&lt;/h2&gt;
&lt;p&gt;OCI 钩子方案能用，但有个根本缺陷：&lt;strong&gt;每个容器运行时都必须知道 NVIDIA 的钩子&lt;/strong&gt;，在厂商中立的规范里塞进了一个厂商专属的钩子。2021 年，NVIDIA、Red Hat 等共同创建了容器设备接口（Container Device Interface，CDI）标准，现由 CNCF 托管。&lt;/p&gt;
&lt;p&gt;CDI 是一份声明式 YAML 规范，描述让一个设备在容器中可用所需的一切：设备节点、库挂载、环境变量和钩子。规范生成一次、存放在 &lt;code&gt;/etc/cdi/&lt;/code&gt;，任何支持 CDI 的运行时读取即可注入设备，无需任何 NVIDIA 专属代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# CDI 设备命名&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nvidia.com/gpu&lt;span class="o"&gt;=&lt;/span&gt;all &lt;span class="c1"&gt;# 所有 GPU&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nvidia.com/gpu&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="c1"&gt;# 仅 GPU 0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nvidia.com/mig-1g.10gb&lt;span class="o"&gt;=&lt;/span&gt;0:0 &lt;span class="c1"&gt;# MIG 实例&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 在 Docker 中使用 CDI（需要 Docker 25+）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker run --device&lt;span class="o"&gt;=&lt;/span&gt;nvidia.com/gpu&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; nvidia/cuda:12.6.0-base nvidia-smi&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="alert alert-note-container"&gt;
&lt;div class="alert-note-title px-2"&gt;
CDI 与 DRA 的关系
&lt;/div&gt;
&lt;div class="alert-note px-2"&gt;
DRA 路径（见&lt;a href="../../data-plane/dra/"&gt;数据平面·DRA&lt;/a&gt;）的设备注入同样依赖 CDI 兼容的运行时。CDI 把“注入”标准化，DRA 把“声明与调度”标准化，两者是上下游关系，不是竞争关系。
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="完整安装实践"&gt;完整安装实践&lt;/h2&gt;
&lt;p&gt;在 GPU 节点上的四步（Kubernetes 场景通常由 &lt;a href="../../control-plane/gpu-operator/"&gt;GPU Operator&lt;/a&gt; 代劳，但手工走一遍能建立完整心智模型）：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 第 1 步：在主机上安装 NVIDIA 驱动（Ubuntu 22.04/24.04）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-get install -y linux-headers-&lt;span class="k"&gt;$(&lt;/span&gt;uname -r&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-get install -y nvidia-driver-570
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo reboot
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 验证：nvidia-smi 应显示 Driver Version: 570.x.x, CUDA Version: 13.x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 第 2 步：安装 NVIDIA Container Toolkit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;|&lt;/span&gt; sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;|&lt;/span&gt; sed &lt;span class="s1"&gt;&amp;#39;s#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;|&lt;/span&gt; sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; sudo apt-get install -y nvidia-container-toolkit&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 第 3 步：配置容器运行时（containerd 为 Kubernetes 默认）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo nvidia-ctk runtime configure --runtime&lt;span class="o"&gt;=&lt;/span&gt;containerd
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl restart containerd
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 第 4 步：验证&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker run --rm --gpus all nvidia/cuda:12.6.0-base-ubuntu22.04 nvidia-smi
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 应打印容器内的 nvidia-smi 输出&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="关键-nvidia-基础镜像选型"&gt;关键 NVIDIA 基础镜像选型&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;镜像标签模式&lt;/th&gt;
&lt;th&gt;包含内容&lt;/th&gt;
&lt;th&gt;适用场景&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nvcr.io/nvidia/cuda:&amp;lt;ver&amp;gt;-base-&amp;lt;os&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;仅 CUDA 运行时（libcudart），无开发工具&lt;/td&gt;
&lt;td&gt;最小推理容器&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nvcr.io/nvidia/cuda:&amp;lt;ver&amp;gt;-runtime-&amp;lt;os&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;基础版 + cuBLAS、cuDNN 运行时库&lt;/td&gt;
&lt;td&gt;运行预编译的 CUDA 应用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nvcr.io/nvidia/cuda:&amp;lt;ver&amp;gt;-devel-&amp;lt;os&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;完整工具链：nvcc、cuDNN、全部头文件&lt;/td&gt;
&lt;td&gt;从源码构建 CUDA 应用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nvcr.io/nvidia/pytorch:&amp;lt;ver&amp;gt;-py3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;完整 PyTorch + CUDA + cuDNN + NCCL&lt;/td&gt;
&lt;td&gt;开箱即用的深度学习训练/推理&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nvcr.io/nvidia/tensorflow:&amp;lt;ver&amp;gt;-tf2-py3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;TF2 + CUDA + cuDNN 栈&lt;/td&gt;
&lt;td&gt;TensorFlow 工作负载&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nvcr.io/nvidia/tritonserver:&amp;lt;ver&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Triton 推理服务器二进制&lt;/td&gt;
&lt;td&gt;生产模型服务&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;figcaption class="text-center mb-3"&gt;
表 1: NVIDIA 官方基础镜像速查
&lt;/figcaption&gt;
&lt;p&gt;选型原则与&lt;a href="../../fundamentals/gpu-memory-management/"&gt;显存管理&lt;/a&gt;的教训一致：devel 镜像体积数倍于 base，运行时镜像只装运行时库；除非你要编译，否则不要用 devel。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;NVIDIA Container Toolkit 的四个组件构成一条注入链：nvidia-container-runtime 把钩子写进 OCI 规范，runc 在容器启动前执行钩子，钩子调用 libnvidia-container 完成设备与库的绑定挂载，nvidia-ctk 负责配置与诊断。CDI 把这套厂商机制标准化，成为现代运行时与 DRA 的共同底座。排障时按“容器里有没有 &lt;code&gt;/dev/nvidia*&lt;/code&gt; → 有没有 &lt;code&gt;NVIDIA_VISIBLE_DEVICES&lt;/code&gt; → 运行时配置对不对”的顺序自底向上检查，绝大多数“容器里看不见 GPU”的问题都能定位。&lt;/p&gt;</content:encoded></item></channel></rss>