解决Docker容器无法识别宿主机cuda驱动-报错Error 804
解决 Docker 容器内 “Error 804: forward compatibility was attempted on non supported HW” 问题
问题现象
在 Docker 容器内运行 PyTorch 等深度学习框架时,执行 torch.cuda.is_available() 返回 False,并出现以下警告:
UserWarning: CUDA initialization: Unexpected error from cudaGetDeviceCount().
Did you run some cuda functions before calling NumCudaDevices() that might have already set an error?
Error 804: forward compatibility was attempted on non supported HW
(Triggered internally at /pytorch/c10/cuda/CUDAFunctions.cpp:119.)
此时宿主机执行 nvidia-smi 正常显示 GPU 信息,但容器内无法识别 CUDA 设备。
原因分析
该错误是由于容器内的 CUDA 兼容库与宿主机 NVIDIA 驱动版本不匹配导致的。
具体来说,容器镜像(特别是基于 CUDA 的镜像)通常会在 /usr/local/cuda/compat 目录下预置一些兼容库文件,目的是让新版 CUDA 能够运行在较旧的驱动上。然而,当宿主机驱动版本较新时,这些预置的兼容库反而会造成冲突,导致 CUDA 初始化失败并抛出 “Error 804”。
简单来说:容器内的兼容库阻碍了容器直接使用宿主机的驱动。
解决方案
第一步:安装 NVIDIA Container Toolkit(若未安装)
首先确保宿主机已正确安装 nvidia-container-toolkit,这是 Docker 能够调用 GPU 的基础。
安装nvidia-container-toolkit并重启docker
# 添加 NVIDIA 仓库密钥
# 添加 GPG 密钥(使用 sudo)
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
# 添加软件源
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
# 更新包列表并安装
sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit
# 配置 Docker
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
# 配置 Docker
nvidia-ctk runtime configure --runtime=docker
# 重启 Docker
systemctl restart docker
验证安装
docker run --rm --gpus all nvidia/cuda:12.0-base nvidia-smi
第二步:检查并删除冲突的兼容库
进入出现问题的容器:
docker exec -it <容器名> /bin/bash
在容器内执行以下命令查看 CUDA 兼容库目录:
ls -la /usr/local/cuda/compat
同时,在宿主机查看驱动版本:
nvidia-smi
关键判断:如果容器内的 /usr/local/cuda/compat 目录存在,且宿主机驱动版本较新(通常驱动版本与容器镜像的 CUDA 版本差距较大时),该目录下的兼容库可能会导致冲突。
临时修复:直接删除目录
rm -rf /usr/local/cuda/compat
删除后退出容器并重启:
exit
docker restart <容器名>
验证修复
重新进入容器并测试 CUDA 是否可用:
docker exec -it <容器名> /bin/bash
python -c "import torch; print('CUDA available:', torch.cuda.is_available())"
如果返回 True,说明问题已解决。
第三步:永久修复方案
临时删除的方式在容器重建后需要重复操作。推荐以下两种永久性修复方案:
方案一:基于原镜像构建新镜像
创建一个 Dockerfile:
FROM <原镜像名称:标签>
# 删除冲突的 CUDA 兼容库
RUN rm -rf /usr/local/cuda/compat
# 可选:设置环境变量确保 CUDA 正常工作
ENV CUDA_VISIBLE_DEVICES=0
ENV LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH
构建并运行:
docker build -t <新镜像名称> .
docker run -d --gpus all --name <容器名> <新镜像名称> tail -f /dev/null
方案二:使用启动脚本自动删除
创建一个启动脚本 entrypoint.sh:
#!/bin/bash
# 删除冲突的 CUDA 兼容库
rm -rf /usr/local/cuda/compat
# 执行原命令
exec "$@"
在 Dockerfile 中复制并设置为入口点:
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
方案三:docker run 时挂载空目录覆盖(不推荐)
docker run -d \
--gpus all \
--mount type=tmpfs,destination=/usr/local/cuda/compat \
<其他参数> \
<镜像名>
完整验证流程
修复完成后,建议执行以下完整验证:
# 1. 检查容器状态
docker ps | grep <容器名>
# 2. 进入容器
docker exec -it <容器名> /bin/bash
# 3. 查看 CUDA 版本
nvcc --version
# 4. 测试 PyTorch CUDA
python -c "import torch; print('CUDA version:', torch.version.cuda); print('Available:', torch.cuda.is_available()); print('Device count:', torch.cuda.device_count())"
# 5. 运行 nvidia-smi
nvidia-smi
总结
Error 804 的根本原因是容器内 CUDA 兼容库与宿主机驱动的冲突。解决方法很简单:
- 确保宿主机正确安装了
nvidia-container-toolkit - 删除容器内
/usr/local/cuda/compat目录 - 通过构建新镜像或修改启动脚本实现永久修复
这个问题在混合使用不同版本 CUDA 镜像和驱动时较为常见,掌握这个排查思路可以快速解决类似问题。
更多推荐
所有评论(0)