Kylin Linux V10实战:手把手教你离线部署NVIDIA Container Toolkit(含避坑指南)
在企业级AI应用开发和部署中,内网或无外网环境是常态。尤其是在使用国产操作系统如银河麒麟Kylin Linux Advanced Server V10时,如何高效、稳定地部署GPU容器化环境,成为许多技术团队面临的挑战。NVIDIA Container Toolkit作为连接容器运行时与GPU硬件的关键桥梁,其离线部署的复杂性和系统兼容性问题常常让工程师们头疼不已。
本文将基于实际项目经验,深入剖析在Kylin V10系统上离线部署NVIDIA Container Toolkit的全过程。不同于简单的在线安装教程,我们将重点关注依赖冲突解决、SELinux策略调整、国内镜像源适配等核心痛点,并提供经过实测验证的完整解决方案。无论你是系统管理员、AI平台工程师,还是需要在隔离环境中部署GPU计算服务的开发者,这篇文章都将为你提供切实可行的技术路径。
1. 环境准备与前置检查
在开始部署之前,充分的准备工作能够避免后续80%的问题。Kylin V10基于RHEL/CentOS体系,但在软件包依赖和内核模块管理上有其特殊性,需要特别注意。
1.1 系统环境确认
首先,我们需要确认系统的基本信息和当前状态。打开终端,执行以下命令:
# 查看系统版本信息 cat /etc/os-release uname -r # 检查GPU硬件状态 lspci | grep -i nvidia # 验证NVIDIA驱动是否已安装 nvidia-smi注意:NVIDIA Container Toolkit要求GPU驱动版本至少为418.81.07。如果尚未安装驱动,需要先完成驱动部署。在Kylin V10上,建议使用NVIDIA官方提供的.run安装包,避免使用系统仓库中可能不兼容的版本。
1.2 容器运行时环境准备
NVIDIA Container Toolkit支持多种容器运行时,包括Docker、containerd、Podman等。根据你的实际使用场景选择合适的运行时。以下是各运行时的适用场景对比:
| 容器运行时 | 推荐场景 | Kylin V10兼容性 | 离线部署复杂度 |
|---|---|---|---|
| Docker | 传统容器化应用、开发测试环境 | 良好 | 中等 |
| containerd | Kubernetes生产环境、云原生应用 | 良好 | 中等 |
| Podman | Rootless容器、安全敏感环境 | 良好 | 较低 |
| CRI-O | 纯Kubernetes环境 | 一般 | 较高 |
如果选择Docker,需要先完成离线安装。以下是基于Kylin V10的Docker离线安装步骤:
# 1. 创建临时工作目录 mkdir -p /opt/docker_offline cd /opt/docker_offline # 2. 在有外网的环境中提前下载所需RPM包 # 假设已下载以下包到当前目录: # docker-ce-25.0.4-1.el7.x86_64.rpm # docker-ce-cli-25.0.4-1.el7.x86_64.rpm # containerd.io-1.6.28-3.1.el7.x86_64.rpm # docker-ce-rootless-extras-25.0.4-1.el7.x86_64.rpm # docker-buildx-plugin-0.12.1-1.el7.x86_64.rpm # docker-compose-plugin-2.24.6-1.el7.x86_64.rpm # 3. 安装依赖包(需提前准备) yum localinstall -y container-selinux-2.164.1-1.module_el8.6.0+1106+9dcb22f7.noarch.rpm # 4. 安装Docker RPM包 rpm -ivh --nodeps *.rpm # 5. 启动并设置开机自启 systemctl enable docker systemctl start docker # 6. 验证安装 docker version1.3 离线资源包准备
在内网环境中,所有依赖包都需要提前下载并传输到目标服务器。以下是NVIDIA Container Toolkit离线部署所需的核心组件:
- NVIDIA Container Toolkit RPM包:包括
nvidia-container-toolkit、libnvidia-container等 - 依赖包:
libcap、libseccomp等系统库 - 容器运行时配置工具:
nvidia-container-runtime
建议在有外网访问权限的Kylin V10系统中,使用以下命令下载所有必要组件:
# 创建下载目录 mkdir -p /opt/nvidia-offline cd /opt/nvidia-offline # 配置临时仓库(仅用于下载) curl -s -L https://nvidia.github.io/libnvidia-container/stable/rpm/nvidia-container-toolkit.repo | \ tee /etc/yum.repos.d/nvidia-container-toolkit.repo # 下载所有相关RPM包及其依赖 repotrack nvidia-container-toolkit repotrack libnvidia-container1 repotrack libnvidia-container-tools repotrack nvidia-container-toolkit-base # 打包所有下载的RPM tar -czf nvidia-container-toolkit-offline.tar.gz *.rpm将生成的tar包传输到内网服务器,即可开始离线安装。
2. 离线安装NVIDIA Container Toolkit
2.1 RPM包安装与依赖解决
将离线资源包上传到目标服务器后,按以下步骤进行安装:
# 1. 解压资源包 tar -xzf nvidia-container-toolkit-offline.tar.gz -C /opt/nvidia-offline/ cd /opt/nvidia-offline # 2. 安装依赖包(按顺序安装以避免依赖冲突) rpm -ivh libcap-*.rpm rpm -ivh libseccomp-*.rpm rpm -ivh libnvidia-container1-*.rpm rpm -ivh libnvidia-container-tools-*.rpm # 3. 安装主工具包 rpm -ivh nvidia-container-toolkit-base-*.rpm rpm -ivh nvidia-container-toolkit-*.rpm # 4. 验证安装 nvidia-ctk --version在Kylin V10上,可能会遇到以下依赖冲突问题及解决方案:
问题1:libcuda.so.1版本冲突
错误:依赖检测失败: libcuda.so.1()(64bit) 被 nvidia-container-toolkit-1.18.0-1.x86_64 需要解决方案:
# 检查当前系统中的libcuda版本 find /usr/lib64 -name "libcuda.so*" # 如果版本不匹配,创建符号链接(假设实际版本为libcuda.so.1.1) ln -sf /usr/lib64/libcuda.so.1.1 /usr/lib64/libcuda.so.1 # 更新动态链接库缓存 ldconfig问题2:与系统自带容器工具冲突
错误:文件 /usr/bin/containerd 来自包 containerd.io-1.6.28-3.1.el7.x86_64解决方案:
# 使用--replacefiles参数强制替换 rpm -ivh --replacefiles nvidia-container-toolkit-*.rpm2.2 配置容器运行时
根据你选择的容器运行时,进行相应的配置。以下是各运行时的配置方法:
2.2.1 Docker配置
# 1. 配置Docker使用NVIDIA运行时 nvidia-ctk runtime configure --runtime=docker # 2. 检查生成的配置文件 cat /etc/docker/daemon.json # 3. 重启Docker服务 systemctl restart docker # 4. 验证配置 docker info | grep -i runtime生成的/etc/docker/daemon.json文件应包含类似以下内容:
{ "runtimes": { "nvidia": { "path": "/usr/bin/nvidia-container-runtime", "runtimeArgs": [] } }, "default-runtime": "nvidia" }2.2.2 containerd配置(Kubernetes环境推荐)
# 1. 生成containerd配置 nvidia-ctk runtime configure --runtime=containerd # 2. 检查生成的配置文件 cat /etc/containerd/config.toml | grep -A5 -B5 "nvidia" # 3. 重启containerd服务 systemctl restart containerd # 4. 验证配置 ctr version2.2.3 Podman配置(Rootless模式)
对于Podman,NVIDIA推荐使用CDI(Container Device Interface)方式:
# 1. 生成CDI配置 nvidia-ctk cdi generate --output=/etc/cdi/nvidia.yaml # 2. 验证GPU设备可访问 podman run --rm --device nvidia.com/gpu=all \ nvidia/cuda:12.0.0-base-ubuntu20.04 nvidia-smi2.3 SELinux策略调整
Kylin V10默认启用SELinux,这可能导致容器无法正常访问GPU设备。以下是解决方案:
# 1. 检查当前SELinux状态 getenforce # 2. 临时设置为permissive模式(测试用) setenforce 0 # 3. 安装SELinux策略包(如果可用) # 注意:Kylin V10可能需要特定版本,可从官方镜像站获取 yum localinstall -y container-selinux-*.rpm # 4. 创建自定义SELinux策略模块 cat > nvidia-container.te << EOF module nvidia-container 1.0; require { type container_runtime_t; type nvidia_device_t; class chr_file { read write open ioctl }; } allow container_runtime_t nvidia_device_t:chr_file { read write open ioctl }; EOF # 5. 编译并安装策略模块 checkmodule -M -m -o nvidia-container.mod nvidia-container.te semodule_package -o nvidia-container.pp -m nvidia-container.mod semodule -i nvidia-container.pp # 6. 恢复SELinux强制模式 setenforce 1如果以上方法不可行,可以考虑在确保安全的前提下,将SELinux设置为permissive模式:
# 修改SELinux配置文件 sed -i 's/SELINUX=enforcing/SELINUX=permissive/g' /etc/selinux/config # 重启系统使配置生效 reboot重要提示:在生产环境中修改SELinux策略需谨慎,建议先与安全团队沟通,并在测试环境中充分验证。
3. 国内镜像源配置与优化
在内网环境中,合理配置镜像源可以显著提升部署效率和稳定性。以下是针对Kylin V10的镜像源配置方案。
3.1 系统YUM源配置
Kylin V10默认使用官方源,在内网环境下需要配置本地源或内部镜像源:
# 1. 备份原有源配置 mkdir -p /etc/yum.repos.d/backup mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/backup/ # 2. 创建本地源配置文件 cat > /etc/yum.repos.d/kylin-local.repo << EOF [local-base] name=Kylin Linux Advanced Server V10 - Base baseurl=file:///mnt/kylin-repo/BaseOS enabled=1 gpgcheck=0 [local-appstream] name=Kylin Linux Advanced Server V10 - AppStream baseurl=file:///mnt/kylin-repo/AppStream enabled=1 gpgcheck=0 EOF # 3. 挂载本地镜像(假设镜像文件为kylin-v10.iso) mount -o loop /path/to/kylin-v10.iso /mnt/kylin-repo # 4. 清理并重建缓存 yum clean all yum makecache3.2 Docker镜像加速配置
对于Docker,配置国内镜像加速器可以加快镜像拉取速度:
# 1. 创建或修改Docker daemon配置 cat > /etc/docker/daemon.json << EOF { "registry-mirrors": [ "https://docker.mirrors.ustc.edu.cn", "https://hub-mirror.c.163.com", "https://mirror.baidubce.com" ], "insecure-registries": [ "your-internal-registry:5000" ], "runtimes": { "nvidia": { "path": "/usr/bin/nvidia-container-runtime", "runtimeArgs": [] } }, "default-runtime": "nvidia" } EOF # 2. 重启Docker服务 systemctl restart docker # 3. 验证配置 docker info | grep -A5 "Registry Mirrors"3.3 NVIDIA容器镜像加速
对于NVIDIA官方容器镜像,可以使用国内镜像站加速:
# 1. 创建镜像拉取脚本 cat > /usr/local/bin/pull-nvidia-image << 'EOF' #!/bin/bash IMAGE=$1 MIRROR_IMAGE=$(echo $IMAGE | sed 's/nvcr.io/nvidia-mirror.cn/g') # 尝试从镜像站拉取 docker pull $MIRROR_IMAGE 2>/dev/null if [ $? -eq 0 ]; then # 重新打标签 docker tag $MIRROR_IMAGE $IMAGE echo "Successfully pulled from mirror: $MIRROR_IMAGE" else # 回退到官方源(需要外网) docker pull $IMAGE echo "Pulled from official source: $IMAGE" fi EOF chmod +x /usr/local/bin/pull-nvidia-image # 2. 使用示例 pull-nvidia-image nvidia/cuda:12.0.0-base-ubuntu20.043.4 离线镜像仓库搭建
对于完全离线的环境,建议搭建私有镜像仓库:
# 1. 拉取registry镜像(在有外网的环境中) docker pull registry:2 # 2. 导出镜像 docker save -o registry-2.tar registry:2 # 3. 在内网服务器导入镜像 docker load -i registry-2.tar # 4. 运行私有仓库 docker run -d \ -p 5000:5000 \ --restart=always \ --name registry \ -v /data/registry:/var/lib/registry \ registry:2 # 5. 推送NVIDIA镜像到私有仓库 docker tag nvidia/cuda:12.0.0-base-ubuntu20.04 localhost:5000/nvidia/cuda:12.0.0-base docker push localhost:5000/nvidia/cuda:12.0.0-base4. 测试与验证
完成部署后,需要进行全面的测试验证,确保NVIDIA Container Toolkit正常工作。
4.1 基础功能测试
# 测试1:验证nvidia-ctk命令可用性 nvidia-ctk --version nvidia-ctk config --list # 测试2:验证容器运行时配置 nvidia-ctk runtime list # 测试3:运行测试容器 docker run --rm --gpus all \ nvidia/cuda:12.0.0-base-ubuntu20.04 \ nvidia-smi # 测试4:多GPU测试(如果有多个GPU) docker run --rm --gpus '"device=0,1"' \ nvidia/cuda:12.0.0-base-ubuntu20.04 \ nvidia-smi -L4.2 性能基准测试
为了确保GPU在容器中的性能接近原生环境,可以运行一些基准测试:
# 1. 创建性能测试脚本 cat > /tmp/gpu-benchmark.sh << 'EOF' #!/bin/bash echo "=== GPU信息 ===" nvidia-smi echo -e "\n=== CUDA设备查询 ===" cat > /tmp/cuda_query.cu << 'CUDACODE' #include <stdio.h> #include <cuda_runtime.h> int main() { int deviceCount; cudaGetDeviceCount(&deviceCount); for (int i = 0; i < deviceCount; i++) { cudaDeviceProp prop; cudaGetDeviceProperties(&prop, i); printf("Device %d: %s\n", i, prop.name); printf(" Compute Capability: %d.%d\n", prop.major, prop.minor); printf(" Global Memory: %.2f GB\n", prop.totalGlobalMem / 1024.0 / 1024.0 / 1024.0); } return 0; } CUDACODE nvcc -o /tmp/cuda_query /tmp/cuda_query.cu 2>/dev/null if [ -f /tmp/cuda_query ]; then /tmp/cuda_query fi echo -e "\n=== 矩阵乘法性能测试 ===" cat > /tmp/matmul.cu << 'MATMULCODE' #include <stdio.h> #include <cuda_runtime.h> #include <cublas_v2.h> #define N 4096 int main() { float *A, *B, *C; float *d_A, *d_B, *d_C; size_t size = N * N * sizeof(float); // 分配主机内存 A = (float*)malloc(size); B = (float*)malloc(size); C = (float*)malloc(size); // 初始化数据 for (int i = 0; i < N * N; i++) { A[i] = 1.0f; B[i] = 1.0f; } // 分配设备内存 cudaMalloc(&d_A, size); cudaMalloc(&d_B, size); cudaMalloc(&d_C, size); // 拷贝数据到设备 cudaMemcpy(d_A, A, size, cudaMemcpyHostToDevice); cudaMemcpy(d_B, B, size, cudaMemcpyHostToDevice); // 创建cublas句柄 cublasHandle_t handle; cublasCreate(&handle); // 执行矩阵乘法 float alpha = 1.0f, beta = 0.0f; cudaEvent_t start, stop; cudaEventCreate(&start); cudaEventCreate(&stop); cudaEventRecord(start); cublasSgemm(handle, CUBLAS_OP_N, CUBLAS_OP_N, N, N, N, &alpha, d_A, N, d_B, N, &beta, d_C, N); cudaEventRecord(stop); cudaEventSynchronize(stop); float milliseconds = 0; cudaEventElapsedTime(&milliseconds, start, stop); printf("Matrix %dx%d multiplication time: %.2f ms\n", N, N, milliseconds); printf("Performance: %.2f GFLOPS\n", 2.0 * N * N * N / (milliseconds * 1e6)); // 清理 cublasDestroy(handle); cudaFree(d_A); cudaFree(d_B); cudaFree(d_C); free(A); free(B); free(C); return 0; } MATMULCODE nvcc -o /tmp/matmul /tmp/matmul.cu -lcublas 2>/dev/null if [ -f /tmp/matmul ]; then /tmp/matmul fi EOF # 2. 在容器中运行基准测试 docker run --rm --gpus all \ -v /tmp/gpu-benchmark.sh:/benchmark.sh \ nvidia/cuda:12.0.0-base-ubuntu20.04 \ bash /benchmark.sh4.3 兼容性测试
测试不同CUDA版本的兼容性:
# 测试不同CUDA版本的容器 CUDA_VERSIONS="11.0 11.8 12.0 12.4" for version in $CUDA_VERSIONS; do echo "Testing CUDA $version..." docker run --rm --gpus all \ nvidia/cuda:${version}.0-base-ubuntu20.04 \ nvcc --version | grep release done4.4 持久化测试
验证GPU容器在长时间运行和重启后的稳定性:
# 1. 启动一个长期运行的GPU容器 docker run -d --name gpu-stress-test \ --gpus all \ nvidia/cuda:12.0.0-base-ubuntu20.04 \ bash -c "while true; do nvidia-smi; sleep 60; done" # 2. 监控容器状态 docker logs -f gpu-stress-test & # 3. 重启Docker服务,验证容器恢复 systemctl restart docker sleep 10 docker ps -a | grep gpu-stress-test # 4. 清理测试容器 docker stop gpu-stress-test docker rm gpu-stress-test5. 故障排除与优化建议
在实际部署过程中,可能会遇到各种问题。以下是常见问题的解决方案和优化建议。
5.1 常见问题排查
问题1:容器启动失败,提示"could not select device driver"
现象:
docker: Error response from daemon: could not select device driver "" with capabilities: [[gpu]].解决方案:
# 1. 检查nvidia-container-runtime是否安装 ls -la /usr/bin/nvidia-container-runtime # 2. 检查Docker配置 cat /etc/docker/daemon.json # 3. 重启Docker服务 systemctl restart docker # 4. 检查内核模块 lsmod | grep nvidia # 5. 重新配置运行时 nvidia-ctk runtime configure --runtime=docker --force systemctl restart docker问题2:GPU设备在容器中不可见
现象:容器内运行nvidia-smi无输出或报错。
解决方案:
# 1. 检查设备权限 ls -la /dev/nvidia* # 2. 检查cgroup设备访问权限 docker run --rm --gpus all \ --device /dev/nvidia0:/dev/nvidia0 \ --device /dev/nvidiactl:/dev/nvidiactl \ --device /dev/nvidia-uvm:/dev/nvidia-uvm \ nvidia/cuda:12.0.0-base-ubuntu20.04 nvidia-smi # 3. 检查SELinux策略 getenforce ausearch -m avc -ts recent | grep nvidia # 4. 临时禁用SELinux测试 setenforce 0 docker run --rm --gpus all nvidia/cuda:12.0.0-base-ubuntu20.04 nvidia-smi setenforce 1问题3:版本兼容性问题
现象:特定版本的NVIDIA Container Toolkit与Kylin V10不兼容。
解决方案:
# 1. 查看已安装版本 rpm -qa | grep nvidia-container # 2. 降级到兼容版本(示例) # 首先卸载当前版本 rpm -e nvidia-container-toolkit # 安装特定版本 rpm -ivh nvidia-container-toolkit-1.13.5-1.x86_64.rpm # 3. 验证版本兼容性 nvidia-ctk --version5.2 性能优化建议
优化1:GPU内存分配策略
# 在Docker配置中限制GPU内存使用 cat >> /etc/docker/daemon.json << EOF { "default-runtime": "nvidia", "runtimes": { "nvidia": { "path": "/usr/bin/nvidia-container-runtime", "runtimeArgs": [ "--gpu-memory-fraction=0.8" ] } } } EOF优化2:多容器GPU共享配置
# 使用MIG(Multi-Instance GPU)技术分割GPU # 1. 启用MIG模式 nvidia-smi -mig 1 # 2. 创建GPU实例 nvidia-smi mig -cgi 1g.5gb -C # 3. 在容器中使用特定GPU实例 docker run --rm \ --gpus '"device=0:0"' \ nvidia/cuda:12.0.0-base-ubuntu20.04 \ nvidia-smi优化3:IO性能优化
# 使用NVMe over Fabric或GPUDirect RDMA加速数据传输 # 在Docker配置中添加以下参数 cat >> /etc/docker/daemon.json << EOF { "storage-driver": "overlay2", "storage-opts": [ "overlay2.override_kernel_check=true" ], "exec-opts": ["native.cgroupdriver=systemd"], "log-driver": "json-file", "log-opts": { "max-size": "100m", "max-file": "3" } } EOF5.3 监控与日志
建立完善的监控体系,及时发现和解决问题:
# 1. 创建监控脚本 cat > /usr/local/bin/monitor-gpu-containers.sh << 'EOF' #!/bin/bash echo "=== GPU状态监控 ===" echo "时间: $(date)" echo "" echo "1. 系统GPU状态:" nvidia-smi --query-gpu=index,name,temperature.gpu,utilization.gpu,memory.total,memory.used,memory.free --format=csv echo -e "\n2. 容器GPU使用情况:" docker ps --format "table {{.Names}}\t{{.Status}}" | grep -v NAMES for container in $(docker ps -q); do echo "容器: $(docker inspect --format '{{.Name}}' $container | sed 's/\///')" docker exec $container nvidia-smi --query-gpu=utilization.gpu,memory.used --format=csv 2>/dev/null || echo " 无GPU访问权限" done echo -e "\n3. NVIDIA Container Toolkit服务状态:" systemctl status nvidia-container-toolkit --no-pager -l echo -e "\n4. 最近错误日志:" journalctl -u docker -u nvidia-container-toolkit --since "10 minutes ago" | grep -i error | tail -5 EOF chmod +x /usr/local/bin/monitor-gpu-containers.sh # 2. 设置定时监控 (crontab -l 2>/dev/null; echo "*/5 * * * * /usr/local/bin/monitor-gpu-containers.sh >> /var/log/gpu-monitor.log") | crontab - # 3. 配置日志轮转 cat > /etc/logrotate.d/gpu-monitor << EOF /var/log/gpu-monitor.log { daily rotate 30 compress delaycompress missingok notifempty create 644 root root } EOF5.4 安全加固建议
在确保功能正常的基础上,加强安全配置:
# 1. 限制容器权限 cat >> /etc/docker/daemon.json << EOF { "userns-remap": "default", "no-new-privileges": true, "icc": false, "live-restore": true, "userland-proxy": false } EOF # 2. 配置容器安全策略 cat > /etc/containerd/config.toml << EOF [plugins."io.containerd.grpc.v1.cri".containerd] default_runtime_name = "nvidia" [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia] runtime_type = "io.containerd.runc.v2" [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia.options] BinaryName = "/usr/bin/nvidia-container-runtime" NoNewPrivileges = true Root = "/var/lib/containerd/io.containerd.runtime.v2.task/default" EOF # 3. 定期更新和扫描 # 创建安全更新脚本 cat > /usr/local/bin/security-update-nvidia.sh << 'EOF' #!/bin/bash # 检查安全更新 echo "检查NVIDIA组件安全更新..." rpm -qa | grep nvidia | while read package; do echo "检查包: $package" # 这里可以添加检查逻辑 done # 扫描漏洞 echo -e "\n扫描已知漏洞..." # 可以集成clair或其他漏洞扫描工具 # 生成报告 echo -e "\n安全报告生成时间: $(date)" > /var/log/nvidia-security-report.log echo "系统: $(cat /etc/os-release | grep PRETTY_NAME)" >> /var/log/nvidia-security-report.log echo "内核: $(uname -r)" >> /var/log/nvidia-security-report.log echo "NVIDIA驱动: $(nvidia-smi --query-gpu=driver_version --format=csv,noheader)" >> /var/log/nvidia-security-report.log EOF chmod +x /usr/local/bin/security-update-nvidia.sh通过以上完整的部署流程、测试验证和故障排除指南,你应该能够在Kylin Linux V10系统上成功部署NVIDIA Container Toolkit,并建立起稳定、高效的GPU容器化环境。在实际操作中,记得根据具体的硬件配置和业务需求调整相关参数,并始终保持对系统日志和监控数据的关注,这样才能确保生产环境的稳定运行。