4. 在Jetson上安装Docker
Jetson平台与普通x86服务器在Docker部署上存在本质差异:其GPU(NVIDIA Tegra系列)无法通过标准nvidia-docker2直接驱动,必须借助NVIDIA官方为嵌入式平台定制的nvidia-container-runtime,将GPU、VPU(视频编解码单元)及CUDA库以容器内设备节点的方式暴露给应用。本章将完整演示在JetPack 5.x/6.x(Ubuntu 20.04/22.04)环境下,通过apt源安装Docker Engine、配置NVIDIA容器运行时,并执行三层验证(版本、GPU可见性、实际算力调用)的标准化流程。
4.1 核心原理:为什么Jetson不能直接使用标准nvidia-docker2
在x86服务器上,NVIDIA GPU通过PCIe总线与CPU通信,驱动直接管理硬件。而Jetson的GPU(如Ampere架构的GA10B)集成在Tegra SoC内,与CPU共享统一内存(Unified Memory),且其设备节点、固件加载路径与x86平台完全不同。标准nvidia-docker2依赖nvidia-container-cli去探测PCIe设备并注入/dev/nvidia*节点,但Jetson上这些节点并不存在——取而代之的是/dev/nvidia-uvm、/dev/nvidia-usb等Tegra特有节点。
NVIDIA为此提供了nvidia-container-runtime的Jetson专用分支,它通过读取/etc/nvidia-container-runtime/config.toml中的nvidia-driver-versions和nvidia-require-jetson标记,自动将Jetson的GPU设备节点、CUDA用户态库(libcuda.so、libnvidia-ptxjitcompiler.so等)以及VPU固件映射到容器内。其核心机制是:
- 设备节点注入:运行时启动时扫描
/dev下与NVIDIA相关的节点,通过--device参数动态挂载到容器。 - 库文件绑定:将宿主机的
/usr/lib/aarch64-linux-gnu/tegra、/usr/lib/aarch64-linux-gnu/libcuda.so.1等路径绑定到容器内相同位置。 - 环境变量传递:自动设置
NVIDIA_VISIBLE_DEVICES=all、NVIDIA_DRIVER_CAPABILITIES=compute,utility等变量,供容器内应用感知GPU。
架构对比速查表
| 对比项 | x86服务器 | Jetson平台 |
|---|---|---|
| GPU接口 | PCIe独立显卡 | SoC集成,统一内存 |
| 设备节点 | /dev/nvidia0, /dev/nvidiactl | /dev/nvidia-uvm, /dev/nvidia-usb |
| 驱动加载 | 内核模块 nvidia.ko | 内核模块 nvgpu.ko + 固件 |
| 容器运行时 | nvidia-container-runtime(标准版) | nvidia-container-runtime(Jetson分支) |
| CUDA库路径 | /usr/lib/x86_64-linux-gnu | /usr/lib/aarch64-linux-gnu/tegra |
| 典型镜像 | nvidia/cuda:12.2-base-ubuntu20.04 | nvcr.io/nvidia/l4t-base:r36.2.0 |
4.2 操作流程:从apt源到运行时配置
以下步骤在Jetson Orin NX(JetPack 6.0,Ubuntu 22.04)上验证通过,适用于所有Jetson系列(Xavier NX、AGX Orin等)。全程需要sudo权限,建议先执行sudo apt update确保系统源正常。
步骤1:安装Docker Engine(apt方式)
# 1. 安装依赖包
sudo apt install -y apt-transport-https ca-certificates curl software-properties-common
# 2. 添加Docker官方GPG密钥(注意:Jetson是arm64架构)
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# 3. 添加apt源(使用arm64架构标识)
echo "deb [arch=arm64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list
# 4. 安装Docker Engine
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
# 5. 将当前用户加入docker组(避免每次sudo)
sudo usermod -aG docker $USER
newgrp docker
# 6. 启动并设置开机自启
sudo systemctl enable docker --now
安装完成后,执行docker version应能看到Client和Server版本信息。若Server部分报错,检查sudo systemctl status docker查看日志。
步骤2:配置nvidia-container-runtime
# 1. 添加NVIDIA官方apt源(Jetson专用)
curl -s -L https://nvidia.github.io/nvidia-container-runtime/gpgkey | sudo apt-key add -
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-container-runtime/$distribution/nvidia-container-runtime.list | sudo tee /etc/apt/sources.list.d/nvidia-container-runtime.list
# 2. 安装运行时
sudo apt update
sudo apt install -y nvidia-container-runtime
# 3. 验证运行时安装
which nvidia-container-runtime
# 应输出 /usr/bin/nvidia-container-runtime
# 4. 修改Docker守护进程配置
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<'EOF'
{
"runtimes": {
"nvidia": {
"path": "/usr/bin/nvidia-container-runtime",
"runtimeArgs": []
}
},
"default-runtime": "nvidia"
}
EOF
# 5. 重启Docker使配置生效
sudo systemctl restart docker
关键注意点:Jetson的daemon.json中不要添加"nvidia-container-cli"相关参数(如nvidia-container-cli --no-persistenced),因为Jetson分支不使用CLI模式,而是直接通过运行时hook注入设备。若添加会导致容器启动失败,报错nvidia-container-cli: initialization error。
步骤3:验证安装(三层检查)
# 第一层:Docker版本与运行时识别
docker version --format '{{.Server.Runtimes}}'
# 应输出 map[nvidia:0x4000012345] 或类似,确认nvidia运行时已注册
# 第二层:GPU设备可见性(使用官方L4T基础镜像)
docker run --rm --runtime=nvidia nvcr.io/nvidia/l4t-base:r36.2.0 nvidia-smi
# 应输出Jetson GPU信息,包括名称、显存(统一内存)、CUDA版本
# 第三层:实际算力调用(运行CUDA向量加法示例)
docker run --rm --runtime=nvidia nvcr.io/nvidia/l4t-cuda:11.4.0-devel-ubuntu20.04 \
sh -c "echo '#include <cuda_runtime.h>
#include <iostream>
int main() {
int count; cudaGetDeviceCount(&count);
std::cout << \"CUDA devices: \" << count << std::endl;
return 0;
}' > test.cu && nvcc test.cu -o test && ./test"
# 应输出 CUDA devices: 1
4.3 案例拆解:从“容器内看不到GPU”到完整运行YOLOv5
背景与约束:某团队在Jetson AGX Orin 64GB上部署YOLOv5s目标检测服务,JetPack 5.1.2,已按常规流程安装Docker和nvidia-container-runtime。但执行docker run --rm nvcr.io/nvidia/l4t-base:r35.4.1 nvidia-smi时报错:
docker: Error response from daemon: failed to create task for container: failed to initialize nvidia container runtime: no devices found.
初始现象:运行时无法找到GPU设备。检查宿主机ls /dev/nvidia*发现只有/dev/nvidia-uvm和/dev/nvidia-usb,缺少/dev/nvidia0和/dev/nvidiactl。
分析判断过程:
- 首先确认宿主机GPU驱动正常:执行
nvidia-smi,输出正常,说明驱动层无问题。 - 检查
/etc/nvidia-container-runtime/config.toml,发现nvidia-require-jetson = false,这是关键错误——Jetson分支必须显式启用该选项。 - 进一步查看
daemon.json,发现误添加了"nvidia-container-cli"参数,导致运行时走了x86路径。
实际操作步骤:
# 1. 修正config.toml
sudo sed -i 's/nvidia-require-jetson = false/nvidia-require-jetson = true/' /etc/nvidia-container-runtime/config.toml
# 2. 清理daemon.json中的多余参数
sudo tee /etc/docker/daemon.json <<'EOF'
{
"runtimes": {
"nvidia": {
"path": "/usr/bin/nvidia-container-runtime",
"runtimeArgs": []
}
},
"default-runtime": "nvidia"
}
EOF
# 3. 重启服务
sudo systemctl restart docker
sudo systemctl restart nvidia-container-runtime
# 4. 重新验证
docker run --rm --runtime=nvidia nvcr.io/nvidia/l4t-base:r35.4.1 nvidia-smi
结果对比:修复后,nvidia-smi正确输出AGX Orin的GPU信息(Ampere架构,64GB统一内存,CUDA 11.4)。随后拉取ultralytics/yolov5:latest镜像,挂载/dev/video0摄像头设备,成功运行实时检测,帧率稳定在45FPS。
风险与代价:该问题导致团队排查耗时3小时,主要原因是NVIDIA官方文档对Jetson分支的config.toml修改说明分散在多个页面。复盘经验:Jetson上安装nvidia-container-runtime后,必须检查nvidia-require-jetson是否为true,这是与x86平台最大的配置差异。
经验提醒:若使用JetPack 6.x(CUDA 12.2),镜像标签应使用nvcr.io/nvidia/l4t-base:r36.2.0或l4t-cuda:12.2.0-devel。JetPack 5.x对应r35.x系列,切勿混用,否则会出现libcuda.so.1版本不匹配错误。
4.4 常见误区与总结复盘
| 误区 | 错误表现 | 正确做法 |
|---|---|---|
| 直接安装nvidia-docker2 | apt报错找不到包,或安装后容器无法启动 | 只安装nvidia-container-runtime,不安装nvidia-docker2 |
| daemon.json中设置nvidia-container-cli参数 | 容器启动报nvidia-container-cli: initialization error | 仅设置runtime路径,不添加CLI参数 |
| 使用x86的CUDA镜像 | 容器内报exec format error | 必须使用nvcr.io/nvidia/l4t-*或arm64架构镜像 |
| 忘记设置default-runtime | docker run不带--runtime=nvidia时无法使用GPU | 在daemon.json中设置"default-runtime": "nvidia" |
| 忽略nvidia-require-jetson配置 | 运行时找不到设备节点 | 确保/etc/nvidia-container-runtime/config.toml中该选项为true |
总结复盘:Jetson的Docker部署本质是“设备节点+库文件+环境变量”三重映射的工程。与x86相比,最大的区别在于:
- 设备节点差异:Jetson没有
/dev/nvidia0,而是/dev/nvidia-uvm,运行时通过nvidia-require-jetson识别并映射。 - 库文件路径:CUDA库位于
/usr/lib/aarch64-linux-gnu/tegra,而非标准路径,运行时需显式绑定。 - 镜像架构:必须使用arm64架构的L4T镜像,x86镜像无法运行。
建议在完成安装后,将以下命令保存为verify-jetson-docker.sh脚本,便于快速验证环境:
#!/bin/bash
echo "=== 1. Docker Runtime ==="
docker version --format '{{.Server.Runtimes}}'
echo "=== 2. GPU Device ==="
docker run --rm --runtime=nvidia nvcr.io/nvidia/l4t-base:r36.2.0 nvidia-smi
echo "=== 3. CUDA Compute ==="
docker run --rm --runtime=nvidia nvcr.io/nvidia/l4t-cuda:12.2.0-devel-ubuntu22.04 \
sh -c "nvcc --version | tail -1"
该脚本可在每次系统更新或Docker升级后执行,确保运行时配置未被覆盖。若输出异常,优先检查daemon.json和config.toml两个配置文件。