news 2026/10/7 22:27:40

海光DCU与麒麟V10环境下PaddleSpeech的Docker部署全记录

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
海光DCU与麒麟V10环境下PaddleSpeech的Docker部署全记录

拿到这个任务时,我刚结束在海光CPU+DCU那套环境里的加班调试。领导只丢给我一句话:PaddleSpeech必须跑起来。这里的“环境”不是常见的NVIDIA GPU,而是海光7000系列CPU、海光DCU加速卡,系统是银河麒麟V10,容器选了Docker。这套组合在网上的参考案例很少,一开始我也心里打鼓,但真把每一步踩完之后发现,核心问题其实就那么几个:设备透传、驱动库挂载、飞桨DCU版的适配。这篇文章就把我这次部署的完整过程和踩坑记录整理出来,给同样要在国产化平台上跑语音任务的朋友当一份参考。

1. 部署前必须理清的三件事

部署之前,我花了不少时间做方案选型。很多人一上来就想在麒麟OS裸机上直接装PaddleSpeech,但考虑到后面要迁移、要复现、要脱离物理机环境,Docker几乎是唯一靠谱的选择。海光DCU在驱动层对外暴露为类似GPU的计算设备,但它的运行库、编译工具链跟NVIDIA的那一套完全不一样,这就决定了我们不能直接用社区里的CUDA镜像,也不能指望官方Docker镜像开箱即跑。

1.1 为什么偏偏要在Docker里跑PaddleSpeech

这个问题我反问过自己很多遍。裸机安装最大的痛点是污染系统:PaddleSpeech依赖的Python包、音频库、模型文件非常多,而且版本相互之间还有约束。麒麟OS自带的Python环境、yum依赖又未必跟得上第三方包的要求,一旦装到一半发现系统库被改动,恢复起来相当痛苦。

Docker的好处在于把整个运行环境隔离成一层“薄壳”,宿主机只提供Linux内核、DCU设备和部分驱动库,容器内管好Python环境和机器学习依赖。这样即便容器被搞坏了,删掉重建也就是几分钟的事,宿主机始终干净。更重要的是,容器配置文件可以版本化管理,后续换机器、加节点时直接把启动命令和Dockerfile拿出来就能复制一套环境。

但代价也很直接:容器不是天生就能认识DCU的。Docker本身默认只做资源隔离,不传递宿主机设备,所以我们必须手动把DCU设备节点挂载进容器,同时还必须把海光DTK(DCU Toolkit)的运行时库透传进去,否则容器里的飞桨连设备都枚举不到。

1.2 硬件和系统环境的准备清单

我的测试环境大概是这样:海光CPU,具体型号就不说了,总之x86_64架构,12核心起步,内存32GB,系统盘之外准备了一块数据盘专门给Docker的数据目录用。DCU卡至少有1张,我这次拿了2张来测试多卡透传。

操作系统是银河麒麟V10 SP1,内核版本5.10,兼容CentOS 7/8的软件包生态。这意味着它的yum源跟CentOS体系高度相似,装Docker的时候可以直接参考CentOS的方式做,但小坑也不少,后面会细说。

关键的软件栈就三块:Docker引擎、海光DCU驱动和DTK运行时、PaddleSpeech及对应版本的飞桨DCU版。DCU驱动是提前装好的,我没用容器去装驱动,因为在内核态的东西怎么也隔离不了。验证驱动是否正常的命令是:

ls /dev/dcu* dmesg | grep -i dcu

如果输出里能看到dcu0、dcu1之类的设备节点,说明驱动已经挂上了。没有节点的话,先在宿主机层面调通,再继续搞容器,不然容器里一切都白搭。

1.3 DCU设备在容器中“看不到”的根因

这是整个部署中最容易卡住的地方。很多人从NVIDIA环境切过来,习惯性地以为拉起容器后就能用nvidia-smi,但海光DCU没有这套东西,容器也不会自动感知设备。

DCU设备在Linux下其实就是一个字符设备文件,例如/dev/dcu0、/dev/dcuctl等。Docker通过--device参数可以把这些节点一一映射进容器。但问题是,就算设备节点进了容器,飞桨或者底层运行时还需要调用/opt/rocm下的动态库、头文件之类的东西。如果容器里没有这些库,设备节点相当于一个没有驱动响应的空壳,调用时立刻就会报错。

所以正确思路是:先把DCU设备节点映射进去,再把宿主机上DTK安装目录(通常是/opt/rocm)挂载为只读目录,同时设置好LD_LIBRARY_PATH,让容器内的进程找得到这些运行时库。理清这一点后,后面的操作就顺理成章了。

2. 麒麟OS上的Docker环境搭建与避坑

麒麟V10上装Docker,说简单也简单,说麻烦也麻烦。网上常见的教程都是针对Ubuntu的,什么apt install docker.io、curl -fsSL get.docker.com | sh,放到麒麟上基本行不通。我这次采用的方法是配置合适的yum源后用yum安装,如果你所在的网络环境连外网受限,也可以预先下载好rpm包离线安装。

2.1 安装Docker:在线源与离线包的选择

我这台机器能访问内网软件源,所以直接配置Docker的CentOS兼容仓库。需要注意,麒麟V10兼容的CentOS版本不同,仓库地址要选对——常见的是兼容CentOS 7或CentOS 8。配置方式比较简单:

cat >/etc/yum.repos.d/docker-ce.repo <<'EOF' [docker-ce-stable] name=Docker CE Stable baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/7.9/x86_64/stable/ gpgcheck=0 enabled=1 EOF yum makecache yum install -y docker-ce docker-ce-cli containerd.io systemctl enable --now docker

如果你所在的网络环境访问不了外网镜像源,离线安装也不难:在有一台能联网、系统版本一致的机器上,先拉取docker-ce、docker-ce-cli、containerd.io三个rpm包,拷贝到目标机器后执行yum install -y ./docker-ce-*.rpm就行。离线包安装最大的好处是不依赖网络,坏处是依赖关系偶尔会缺一两个包,碰到时从安装介质里补上即可。

装完第一件事看版本和状态:

docker version systemctl status docker

如果docker version能同时打印Client和Server信息,就说明守护进程正常启动了。很多人在这一步就卡壳,后面的章节我会把典型的启动失败问题单独列出来。

2.2 daemon.json配置:镜像加速与存储位置

麒麟OS上的Docker默认配置比较朴素,直接跑也能用,但作为实际部署,我建议提前把/etc/docker/daemon.json写好。这个文件的作用是全局配置,优先级比命令行参数高,内容包括镜像加速、存储驱动、数据目录等。

我这次的配置如下:

cat >/etc/docker/daemon.json <<'EOF' { "registry-mirrors": [ "https://docker.m.daocloud.io", "https://dockerproxy.com" ], "exec-opts": ["native.cgroupdriver=cgroupfs"], "data-root": "/data/docker", "storage-driver": "overlay2" } EOF systemctl daemon-reload systemctl restart docker

这里有两个值得说的点。第一,registry-mirrors是用来解决Docker镜像拉取慢、超时问题的,典型场景早就不是只有一线城市了,任何地区都可能遇到镜像下载卡住的情况。配置多个国内镜像源之后,docker pull会快很多。第二,>getenforce

如果返回Enforcing,临时关闭一下再做测试:

setenforce 0

KYSEC相关的策略一般可以通过修改配置文件调整,但为了快速验证技术方案,我在测试阶段直接把它关掉了。等整套环境跑通后,再回头把预留的启动参数、设备白名单加进去做合规加固。这里提醒一句:生产环境下不要学我一刀切关安全模块,正确的做法是查阅麒麟安全策略文档,给Docker数据和设备目录加白名单,不过初测阶段为了少踩坑,临时关闭是最高效的路径。

3. 拉取镜像并创建PaddleSpeech容器

Docker引擎Ready之后,最核心的一步来了:选什么基础镜像,怎么透传DCU设备,怎么让容器内的Python环境认得出海光加速卡。这一部分我花了最多的时间,因为不同的镜像、不同的系统库组合会带来各种连锁问题。

3.1 基础镜像选择:别让glibc拖后腿

PaddleSpeech官方建议的Python版本是3.7到3.10,对操作系统的要求不算苛刻。我一开始图省事,直接用官方python:3.7-slim镜像,结果容器里安装飞桨DCU版时直接报错,提示找不到某个GLIBC_3.27符号。后来换成ubuntu:20.04再自己装Python 3.9,问题才解决。

所以我的建议是尽量用基础镜像时选较新的发行版,例如ubuntu:20.04或rockylinux:8,因为飞桨和它依赖的so库对glibc版本有最低要求,太老的基础镜像会带来不少符号缺失问题。麒麟OS虽然本身兼容CentOS 7/8生态,但容器内不一定要依赖麒麟的库,共用宿主机的库反而容易引入不匹配。

如果你有麒麟官方发布的容器基础镜像,那是最好的,优先用它;没有的话,ubuntu:20.04这条路线我在多个版本验证下来是最稳的。

拉取镜像:

docker pull ubuntu:20.04

3.2 创建容器时必加的三个参数

这一步是整个部署的精髓。启动命令我写成下面这样,逐行解释:

docker run -it --name paddlespeech \ --device=/dev/dcu0:/dev/dcu0 \ --device=/dev/dcu1:/dev/dcu1 \ --device=/dev/dcuctl:/dev/dcuctl \ -v /opt/rocm:/opt/rocm:ro \ -v /data/models:/root/.paddlespeech \ -e LD_LIBRARY_PATH=/opt/rocm/lib:/usr/lib64/:$LD_LIBRARY_PATH \ ubuntu:20.04 \ /bin/bash

第一个参数是--device,把DCU设备节点逐个映射进容器。我用2张卡,所以映射了dcu0和dcu1,另外还把控制设备dcuctl也映射进去了。如果你的驱动生成的设备节点名不完全一样,先执行ls -l /dev/dcu*看清楚再写。

第二个参数是-v /opt/rocm:/opt/rocm:ro,把宿主机上海光DTK运行库目录挂进容器。这个目录包含librocblas、libhbrt等核心计算库,飞桨在运行时必须调用。

第三个参数是环境变量LD_LIBRARY_PATH,必须让它优先找到/opt/rocm/lib下的动态库。有些版本的DTK库还依赖/usr/lib64下的一些基础库,所以我也把宿主机的/usr/lib64加到了查找路径里,注意这里只是加入查找路径,不会覆盖容器内已有库。

调试期间我曾经图省事直接加了--privileged,这样确实能让容器访问所有设备,但生产环境不建议这么干。透传该用的设备节点就够了,权限范围越小越好。

3.3 容器内确认DCU设备可见

容器创建并进入bash后,第一步不是急着装PaddleSpeech,而是确认DCU设备真的在容器里:

ls -l /dev/dcu* ls -l /opt/rocm

能看到dcu0、dcu1以及/opt/rocm目录内容,就说明设备和库都透传成功。接下来还要验证飞桨能否识别这些设备。先用pip装一个DCU版的飞桨,稍后第4节会细说,这里只展示验证代码:

python -c "import paddle; paddle.utils.run_check()"

如果运气好,可以看到类似“PaddlePaddle is installed successfully”的输出,并且设备信息里带有DCU相关的描述。如果输出显示设备数为0,那就要回头检查设备映射、LD_LIBRARY_PATH和驱动状态了。

很多人在这一步反复失败,原因是容器内缺少Python或pip。所以创建容器后先装好基础环境再做验证:

apt update && apt install -y python3 python3-pip

为了后续顺手,我习惯把python3软链成python:

ln -sf /usr/bin/python3 /usr/bin/python

4. 容器内安装PaddleSpeech并完成语音识别验证

设备可见性确认没问题后,后面就顺畅多了。PaddleSpeech的安装过程说复杂也复杂,说简单也简单:核心是先把飞桨的DCU版装好,再装PaddleSpeech本体,最后准备一段音频测试一下ASR链路。

4.1 安装DCU版飞桨的关键点

这里的坑主要是:PaddleSpeech安装时会自动拉取一个普通版PaddlePaddle,默认是从PyPI装的CPU版或者CUDA版,根本不知道DCU的存在。如果你直接pip install paddlespeech,它十有八九会把普通PaddlePaddle装进环境,随后飞桨再访问DCU设备就会报“无法找到CUDA驱动”之类的错。

正确的顺序应该是先装海光DTK适配过的飞桨DCU版。海光跟飞桨生态有适配产出,在Python包仓库或DTK工具链文档里能拿到对应的包名和版本,我这次用的版本是paddlepaddle-roit==2.5.2,具体以小版本号为准。安装命令如下:

python -m pip install paddlepaddle-roit==2.5.2

装完后立刻做一次设备检测:

python -c "import paddle; print('dcu count:', paddle.device.cuda.device_count())" python -c "import paddle; print(paddle.device.cuda.get_device_name(0))"

注意打印结果。若输出设备数为1或2,就说明飞桨已经能和DCU通信了。如果输出0,大概率是LD_LIBRARY_PATH没设置好,或者/opt/rocm没有正确挂载。

为了保险,可以在容器内执行:

python -c "import paddle;paddle.utils.run_check()"

它会运行一个小矩阵计算,真正把数据送到DCU上跑一遍,比单纯看设备枚举更有说服力。

4.2 安装PaddleSpeech本体

飞桨DCU版就绪后,开始安装PaddleSpeech。为了避免它把普通PaddlePaddle覆盖掉,我用了--no-deps参数,然后再手动把其余依赖补齐:

python -m pip install paddlespeech==2.5.2 --no-deps -i https://pypi.tuna.tsinghua.edu.cn/simple python -m pip install paddleaudio pyworld sentencepiece librosa -i https://pypi.tuna.tsinghua.edu.cn/simple

这样做的原因很简单:--no-deps让pip不自动解析依赖,从而避免PaddleSpeech把环境里已装好的paddlepaddle-roit当成普通paddlepaddle而强制替换。手动补的这几个包是它运行时的必需项,包括音频处理、特征提取、文本转写等。

装好之后可以用一条简单的命令验证PaddleSpeech是否可导入:

python -c "import paddlespeech; print(paddlespeech.__version__)"

能打印版本号,就说明安装没有硬伤。

4.3 生成测试音频并跑通ASR

PaddleSpeech装上不等于能识别,还需要模型文件和音频输入。第一次运行时会自动下载模型,所以需要保持网络通畅。模型主要包含语音识别用的声学模型和语言模型,体积从几百MB到1GB不等。

测试时我准备了一段中文录音,文件名为zh.wav,采样率16kHz,16bit,单声道。这一步非常重要,PaddleSpeech不少底层的特征提取对采样率有要求,如果你的音频是44.1kHz,建议先转成16kHz再识别,命令可以用ffmpeg:

apt install -y ffmpeg ffmpeg -i input.mp3 -ar 16000 -ac 1 zh.wav

然后执行ASR:

paddlespeech asr --lang zh --input zh.wav

如果模型还没下载过,它会先输出下载进度,下载完成后开始推理,最后打印识别的文本结果。

我也验证了用Python接口调用的方式,方便嵌入代码:

from paddlespeech.cli.asr.infer import ASRExecutor asr = ASRExecutor() result = asr(audio_file="zh.wav", lang="zh") print(result)

在DCU上,推理过程会调用/opt/rocm里的计算库,可以通过htop或者dcuinfo观察卡的使用率。只要能看到DCU工作,就说明整个链路彻底打通了。

PaddleSpeech不仅仅能做ASR,还能做语音合成、声纹识别、标点恢复等。这次先以ASR为验证目标,测试通过后类似的能力都可以在这个Container里按同样思路扩展。

5. 常见问题与排查思路实录

这次部署中踩过的坑,其实大部分在标题里就暗示了:Docker权限错误、服务启动失败、设备不识别、镜像下载慢、网络不通。我整理成了一张速查表,希望你看完能少走弯路。

现象可能原因排查与解决
docker: permission denied while trying to connect to the Docker daemon socket当前用户不在docker组执行sudo usermod -aG docker $USER并重新登录,或者用sudo docker临时运行
Docker服务启动失败,日志里提示iptables相关firewalld/iptables冲突或内核模块未加载先modprobe overlay && modprobe br_netfilter,再关闭或放行防火墙,最后systemctl restart docker
容器启动后ls /dev/dcu*为空--device参数没写全,或者宿主机驱动异常在宿主机执行ls /dev/dcu*,确认节点存在后再写启动参数
飞桨检测不到DCU设备,device_count()为0版本不对或运行库没挂载确认安装的是paddlepaddle-roit而不是普通PaddlePaddle;检查/opt/rocm是否挂载以及LD_LIBRARY_PATH
运行推理时报GLIBC_XX not found基础镜像太旧,glibc版本不够换用ubuntu:20.04或更新的基础镜像,不要用过于精简的镜像
paddlespeech asr下载模型卡住网络问题或默认下载源不稳定手动在宿主机下载模型文件并放到/root/.paddlespeech对应的模型目录,或配置镜像源
pip install超时PyPI源访问慢使用清华、阿里等镜像源,例如-i https://pypi.tuna.tsinghua.edu.cn/simple
容器网络不通,无法apt updateDocker网桥与宿主机防火墙冲突检查firewalld状态,必要时临时systemctl stop firewalld,再重启Docker

5.1 Docker权限错误怎么解决最快

这个问题几乎每个人都会碰到。安装完Docker之后,如果当前用户不在docker组里,直接执行docker ps就会报permission denied while trying to connect to the docker api。最快的办法是把用户加进docker组,然后重新登录会话;不建议动不动就sudo chmod 777 /var/run/docker.sock,那会带来安全隐患。

sudo usermod -aG docker $USER

执行成功后退出终端重新登录,再执行docker ps验证。如果还报错,可以查看socket权限:

ls -l /var/run/docker.sock

正常情况属主是root:docker,权限是rw。如果不是这个状态,说明Docker安装过程中socket权限被修改过,可以重置。

5.2 容器内找不到设备文件,怎么排查

按我前面写的--device参数启动,设备节点一般都能透传进去。但如果宿主机上驱动加载出了问题,哪怕参数写对了也没用。排查时先在宿主机看:

lspci | grep -i dcu dmesg | grep -i dcu ls /dev/dcu*

如果驱动没加载,先处理驱动,比如确认内核模块是否存在,必要时重新加载:

modprobe dcu

然后再启动容器。容器内的设备文件必须与宿主机一一对应,比如宿主机上是/dev/dcu0,容器内也应该是/dev/dcu0,命令里的映射关系不能写反。

5.3 容器内运行库不匹配的问题

海光DCU运行时库往往依赖宿主机上的一些基础系统库,比如libstdc++、libgomp等。容器内如果版本太旧,运行时就会报符号找不到。除了换基础镜像,我还有一个备选方案:把宿主机的/usr/lib64/x86_64-linux-gnu或/usr/lib64挂载进去,然后通过LD_LIBRARY_PATH让动态加载器优先搜索:

-v /usr/lib64:/host-libs:ro -e LD_LIBRARY_PATH=/host-libs:/opt/rocm/lib:$LD_LIBRARY_PATH

这种做法的缺点是可能引发容器内原有库版本冲突,所以只建议在紧急情况下使用,正常情况下还是把基础镜像换新比较干净。

5.4 模型下载失败怎么处理

PaddleSpeech首次运行ASR会去下载模型。如果网络环境受限,下载进度条经常卡住不动。解决方式是手动提前准备好模型文件。

PaddleSpeech模型默认缓存在~/.paddlespeech目录下,目录结构按模型名区分。你可以在有网络的机器上先把对应模型整个目录打包,然后拷贝到容器或挂载目录里。我这次就是把/data/models作为宿主机目录挂载到容器/root/.paddlespeech位置,这样模型文件一次下载,以后重建容器都不用再拉。

5.5 容器内的飞桨和系统库冲突

在整个过程中最容易遇到的一类问题是,PaddleSpeech自动依赖里有一堆音频库,这些库之间可能对OpenMP、libsndfile等版本互相有要求。装的时候不要一次性把所有包全打进去,尽量按需安装。如果遇到libpython版本冲突,我建议直接重建一个干净的容器环境,在容器里专门用python -m venv /opt/venv再装一套虚拟环境,之后所有PaddleSpeech依赖都放进这个venv里,能有效隔离系统Python。

6. 整个部署过程中的一点体会

这次在国产CPU+DCU+麒麟OS上用Docker跑通PaddleSpeech,最大的收获不是“装上了”,而是把容器透传设备和国产计算卡运行库之间的关系彻底理顺了。从NVIDIA转到DCU,思维上最大的转变是:不要把它当作一个依赖某个魔法镜像的“黑盒”,而要理解容器里运行的程序最终需要什么,设备节点、动态库、环境变量这些都要按需提供。

如果让我重新再做一次,我第一件事还是先把宿主机上的DCU驱动和设备节点状态确认清楚,然后再按设备挂载、运行库挂载、飞桨DCU版、PaddleSpeech本体这个顺序推进。每一步都用最简单的命令验证,绝不跳步。

最后再分享一个小技巧:建议把完整的docker run命令整理成shell脚本放到项目仓库里,同时保留一份最终的容器提交镜像。这样团队其他人拿到脚本,或者直接load镜像,就能在另一台海光环境上快速复现整个PaddleSpeech服务,这才是这次部署最大的价值所在。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/7 22:26:16

Windows Server 2019安全加固:服务、网络与账号策略实战指南

简介&#xff1a;一份围绕 Windows Server 2019 操作系统安全配置与系统加固的 Word 技术文档&#xff0c;面向服务器运维人员、网络安全管理者及企业 IT 学习者&#xff0c;聚焦安全基线设置与加固落地&#xff0c;帮助降低网络病毒、木马及恶意程序对服务器带来的攻击风险。资…

作者头像 李华
网站建设 2026/10/7 22:24:38

SSA与扩散模型联合预测AUV高频海浪扰动

1. 为什么传统AUV海浪扰动预测总在“差半拍”——从物理建模失准到数据驱动瓶颈你有没有试过让自主水下航行器&#xff08;AUV&#xff09;在近海执行高精度地形测绘任务&#xff0c;结果刚下潜到20米深度&#xff0c;声呐图像就突然抖成雪花&#xff1f;不是设备故障&#xff…

作者头像 李华
网站建设 2026/10/7 22:23:40

微信小程序开放接口实战:运动数据、地址选择与生物认证

做小程序开发这几年&#xff0c;我见过太多团队把精力全放在页面和交互上&#xff0c;最后却在“用户身份数据怎么安全拿到”这个问题上翻车。尤其是一些看起来不起眼的开放接口——运动数据、收货地址、生物认证&#xff0c;它们单拎出来都不复杂&#xff0c;但一旦放进真实业…

作者头像 李华
网站建设 2026/10/7 22:21:11

基于ControlNet的PLC双CPU冗余控制系统设计与实现要点

简介&#xff1a;这是一份详解基于ControlNet现场总线的PLC双CPU冗余控制系统实现方法的专业技术文献&#xff0c;面向工业自动化工程师、PLC系统设计与维护人员。内容围绕罗克韦尔ControlLogix 756-L55双CPU控制器展开&#xff0c;重点阐述如何通过软件方式实现CPU冗余控制&am…

作者头像 李华
网站建设 2026/10/7 22:21:10

前端异步编程核心:Promise机制、微任务与工程实践全解析

“承诺还是空头支票&#xff1f;”这个题目起得有点损&#xff0c;但也确实点到了Promise的本质。我从2015年前后开始带前端项目&#xff0c;从jQuery时代的$.ajax回调一路写到现在&#xff0c;见过太多人在Promise上栽跟头。有些人把它当成可以穿透一切的“魔法”&#xff0c;…

作者头像 李华
网站建设 2026/10/7 22:20:02

魔力工作台:开源轻量AI编程工作台,一切皆文件、任务可编排

我大概花了两周时间&#xff0c;做了一个叫“魔力工作台”的开源项目&#xff0c;本质上是想给 workbuddy 这类偏闭源、偏重量的 AI 工作台工具提供一个更轻、更可控、也更符合我自己使用习惯的替代方案。说实话&#xff0c;最初只是自己在用&#xff0c;后来发现身边不少同事也…

作者头像 李华