背景近期需要将一套基于 PyTorch 的深度学习工程从传统的 x86_64 架构服务器迁移到物理隔离的内网华为昇腾ARM/aarch64 架构算力集群上。原本以为只是常规的scp传文件和conda activate结果却遭遇了堡垒机限制、硬件架构差异、跨版本 Python 兼容、以及内网断网等一系列问题。本文完整记录了本次迁移的排查逻辑与最终解决方案。总体路径发现跨架构x86 - ARM导致 Conda 环境无法直接迁移 ➔在目标内网机启动昇腾官方 Docker 镜像作为底层底座 ➔在源机器提取纯净版requirements.txt➔在联网机强制下载适配 ARM 目标 Python 版本的.whl离线包 ➔将包传入内网并挂载进容器 ➔利用--no-index和--no-deps完成离线安装一、 网络与传输打破隔离限制1. 多层跳板与路由不通内网的安全策略通常极其严格初始网络架构为本地 - 堡垒机网关 - 内网计算节点。直接尝试 SSH 连接目标节点时报错No route to host。这并非 SSH 服务未启动而是跨网段的路由未放行或防火墙拦截。排查ip route确认路径后联系管理员开通了相应的 ACL 策略。2. Xftp 代理隧道被安全策略拦截为了传文件常规操作是在 Xshell 中建立 SOCKS5 动态隧道然后让 Xftp 走代理。但连接时触发了统一认证网关的拦截[UMA] (tunnel) Permission denied: SSO_PERMISSION_DENIED, Permission denied (code: 11)结论该内网环境的管控策略完全禁用了 SSH 端口转发。最终只能回归合规通道依靠终端自带的 Web 直传或命令行scp将文件推入内网。二、 硬件与存储摸清昇腾底座1. 硬件驱动的“乌龙”进入计算节点后习惯性执行nvidia-smi报错找不到命令lspci也找不到显卡。# 查看具体的 NVIDIA 显卡型号 lspci | grep -i nvidia经过排查发现该节点使用的是华为昇腾 NPU。在国产化架构中必须使用专用的管理工具# 查看昇腾 NPU 设备信息 npu-smi info2. 寻找共享存储与磁盘规划内网节点的本地系统盘通常空间有限极易触发 100% 告警导致宕机。通过df -h检查发现集群挂载了大容量分布式共享存储。最佳实践千万不能将环境或数据集放在~家目录或/下必须重定向至/data或共享存储挂载点使其他节点也可以访问。三、 环境迁移Conda 跨架构的灾难最初方案是使用conda-pack将源服务器上跑通的虚拟环境打包成.tar.gz传到内网解压。参考深度学习模型环境跨平台迁移全指南从 Linux 服务器到本地/堡垒机-CSDN博客解压时报错conda-unpack # 报错 /root/anaconda3/envs/.../bin/python: 1: Syntax error: ) unexpected排查可能是架构不同的问题# 查看CPU架构 arch原因源服务器为 x86_64 架构目标昇腾节点为 aarch64 (ARM) 架构。Conda 环境内的二进制文件和底层 C 扩展库无法跨 CPU 指令集运行且两边 Python 版本相差较大。结论跨架构迁移深度学习环境放弃 Conda转向 Docker 容器化是唯一解。建议删除原来报错的conda环境conda deactivate rm -rf /root/anaconda3/envs/your_env四、容器化破局与设备挂载内网机器上通常会有官方预置的昇腾基础镜像如带有 CANN 和特定版本 PyTorch 的镜像。启动容器时核心难点在于如何将宿主机的 NPU 设备透传给容器。1. 查找已有的镜像列表若有可使用已有的镜像来创建新容器docker images # 查看本地有没有现成的镜像2. 启动命令需包含完整的设备节点与驱动挂载只读挂载:ro可保护宿主机驱动文件docker run -it -d \ --name my_train_env \ --privileged \ --nethost \ --device /dev/davinci0 \ --device /dev/davinci_manager \ --device /dev/devmm_svm \ --device /dev/hisi_hdc \ -v /usr/local/dcmi:/usr/local/dcmi:ro \ -v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi:ro \ -v /usr/local/Ascend/driver/lib64/:/usr/local/Ascend/driver/lib64/:ro \ -v /usr/local/Ascend/driver/version.info:/usr/local/Ascend/driver/version.info:ro \ -v /etc/ascend_install.info:/etc/ascend_install.info:ro \ -v /宿主机代码路径:/workspace \ 已有镜像名 /bin/bash-d让容器在后台一直跑不会一关终端它就死掉--name my_train_env容器名--nethost --ipchost共享宿主机的网络和内存多卡通信必须--device必须显式挂载/dev/davinci0到/dev/davincix共x张卡以及davinci_manager、devmm_svm、hisi_hdc等管理设备容器才能识别到 NPU-v挂载将宿主机的npu-smi工具、驱动库lib64和配置文件挂载进容器解决command not found和libascend_hal.so缺失的问题。-v /...:/workspace将项目代码挂载到容器里的/workspace目录。在宿主机改代码容器里立刻生效注意只挂载自己的目录容器中对挂载目录执行rm -rf *宿主机上那个目录的文件也会删除3. 进入容器docker exec -it my_train_env /bin/bash4. 加载环境变量source /usr/local/Ascend/ascend-toolkit/set_env.sh注意进入容器后必须加载昇腾底层环境变量否则无法调用torch_npu。5. 验证环境前提是源镜像中已包含相关模块# 1. 检查是否能识别卡 npu-smi info # 2. 检查 Python 里的 PyTorch 和 NPU 是否就绪 python3 -c import torch; import torch_npu; print(PyTorch 版本:, torch.__version__); print(NPU 是否可用:, torch.npu.is_available())如果打印True则基本环境已具备* 其他相关命令# 退出容器 exit # 删除容器 docker rm -f 容器名五、 断网环境的依赖安装离线 Wheels 方案容器跑起来后需要安装项目相关依赖包。由于内网隔离容器内无法解析外网域名也无法解析 K8s 内部的 PyPI 镜像源报Temporary failure in name resolution。只能采用离线安装。0. 从已有可运行环境中导出requirement.txt1在源服务器上激活环境并导出# 1. 激活原来能跑通的环境 conda activate your_env # 2. 导出所有的 pip 依赖 pip freeze requirements.txt2过滤不需要的包目标环境已经有了昇腾专属的torch和torch_npu如果把源环境的torch装过去环境会直接炸掉# 过滤掉 torch、numpy、pandas 等底层和易冲突的包保留其余的纯净依赖 grep -v -i -E torch|numpy|pandas|scipy|matplotlib|tensorboard requirements.txt req_clean.txt # 看一眼剩下的内容 cat req_clean.txtreq_clean.txt可能混杂了大量本地路径依赖、NVIDIA CUDA 专属包、老旧的与Python版本不匹配的包。如果不清理直接下载不仅下载会失败传到目标机安装时也会报错No matching distribution found或Exec format error。建议将文件发给大模型让其生成对应的纯净依赖文件req_clean.txt1. 在 x86 外网机上下载 ARM 架构的轮子1借助pip download的跨平台参数直接在 x86 机器上强制下载目标为aarch64和 Python 3.12 的二进制包Wheels# 创建目录 mkdir wheels_arm pip download -r req_clean.txt -d ./wheels_arm \ --platform manylinux2014_aarch64 \ --python-version 312 \ --only-binary:all: \ --use-deprecatedlegacy-resolver--use-deprecatedlegacy-resolverpip不解决依赖冲突注如果遇到某些包解析失败可尝试加上--no-deps参数单独下载主包。2打包传输将wheels目录压缩传输到目标服务器中# 源服务器打包 tar -czvf wheels_arm.tar.gz ./wheels_arm2. 在容器内进行离线安装1进入容器解压上传的wheels包# 目标服务器 # 进入容器 docker exec -it 容器名 /bin/bash #解压二进制包 cd /workspace tar -xzvf wheels_arm.tar.gz2在容器内执行离线安装并强制忽略依赖关系使用--no-deps。pip install --no-index --find-links./wheels_arm -r req_clean.txt --no-deps由于基础镜像中已经包含了完美的 PyTorch 和 torch_npu使用--no-deps可以避免 pip 去覆盖底层核心库。不加 --no-deps可能报错Processing ./wheels_arm/aiohttp-3.14.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl (from -r ./req_clean.txt (line 3)) ERROR: Could not find a version that satisfies the requirement matplotlib (from mmengine) (from versions: none) ERROR: No matching distribution found for matplotlib*3. 可选安装可编辑包导入代码中的自定义模块# 进入源代码包目录 cd /myproject/src pip install -e . --no-deps --no-build-isolation--no-deps只把当前代码作为一个包链接进来不下载和安装任何依赖--no-build-isolation让 pip 直接使用容器内现有的环境进行构建注意事项由于上述安装过程忽略了依赖关系因此后续可能需要补充安装相关包解决方案执行模型代码若报错缺啥补啥直到成功运行参考 [模块六]六、 补丁代码层面的兼容性排雷通过离线安装虽然容器的底层环境CANN、PyTorch、NPU 驱动已经就绪但在直接运行代码时依然可能遭遇大量报错依赖断层与版本不兼容由于手动离线安装引起废弃模块与 API 变更由于 Python 版本跨代引起ModuleNotFoundError: No module named torchdata.datapipes ModuleNotFoundError: No module named pytorch_lightningtorchdata.datapipes模块缺失原因torchdata在 0.10.0 版本后废弃了datapipes模块。解决降级安装旧版单独下载torchdata0.7.1的纯 Python 包进行替换。pytorch_lightning缺包原因离线安装时漏掉了torchmetrics。解决单独下载torchmetrics的 whl 包上传安装。解决方案单独下载对应.whl文件并上传到内网服务器安装1在官网获取所需文件例如针对【torchdata.datapipes模块缺失】问题 Client Challenge找到并下载名为torchdata-0.7.1-py3-none-any.whl的文件2将.whl文件上传到内网服务器3在容器内安装包# 进入容器 docker exec -it 容器名 /bin/bash # 先卸载之前装错的新版本 pip uninstall -y torchdata # 安装刚传上来的本地文件 pip install /workspace/torchdata-0.7.1-py3-none-any.whl* 其他问题项目代码中可能存在绝对路径硬编码原因代码和配置文件中写死了原集群的绝对路径解决将配置文件中的root_dir和data_dir全部替换为当前容器内的挂载路径如/workspace/...。总结与经验沉淀先验架构再看框架进入未知内网先跑uname -m和lscpu国产化机器普遍是aarch64直接抛弃nvidia-smi思维。跨平台离线下载使用pip download --platform manylinux2014_aarch64 --python-version x.x是拯救内网机器的神技。敬畏基础镜像官方打好底层的镜像里PyTorch 和 CANN 的版本是严格绑定的。手工装包时务必使用--no-deps防止依赖被意外覆盖。放弃 Conda 幻想对于跨平台的底层环境迁移Docker 的隔离性与一致性是降维打击。希望这篇踩坑记录能帮到正在进行国产化算力适配的同行。