FunASR OpenAI 兼容 API 的 Kubernetes 部署实战:从 CPU 模板到 MOSS GPU 方案
【免费下载链接】FunASROpen-source speech recognition toolkit for training, inference, streaming ASR, VAD, punctuation, speaker diarization pipelines, and OpenAI-compatible/MCP serving.项目地址: https://gitcode.com/GitHub_Trending/fun/FunASR
导读
本文基于 examples/openai_api/kubernetes/README.md 展开,系统讲解如何在 Kubernetes 集群中部署 FunASR 的 OpenAI 兼容语音识别服务,为 Agent、Web 后端、工作流引擎(如 Dify、n8n)或批处理任务提供内部的语音端点。你将掌握镜像构建与推送、基于 Kustomize 的声明式部署、port-forward 冒烟测试、集群内服务寻址、资源调优参数,以及面向 MOSS-Transcribe-Diarize 的 GPU 部署方案;同时会结合仓库内的清单文件与源码,理解每项配置背后的设计意图与安全边界。
部署前置条件与安全边界
在开始之前,请确认环境满足以下条件(原文要求所有命令均在 FunASR 仓库根目录执行,包括另开终端中的命令):
- 已安装 Docker,且拥有一个可写入的镜像仓库(用于存放构建产物);
kubectl已配置好目标集群,且当前账号具备在speech命名空间创建资源的权限;- 集群存在默认 StorageClass,用于为模型缓存 PVC 动态供给存储;
- 本地冒烟测试客户端需要Python 3.10 或更高版本,且不依赖任何第三方 Python 包(smoke_test.py 仅使用标准库
urllib/json/mimetypes)。
需要特别强调的是:ClusterIP 不等于认证。两个清单(CPU 与 MOSS)都没有提供 NetworkPolicy、认证网关、TLS 或请求限额。在允许不可信客户端访问之前,请先阅读服务安全指南。本文给出的验证路径是本地port-forward,而不是暴露公网 Ingress。
清单的设计刻意保持保守,其意图可从 funasr-api.yaml 中逐一印证:
- 服务默认使用
ClusterIP,而非公开的LoadBalancer; FUNASR_DEVICE=cpu为默认值,保证镜像与可移植的 Dockerfile 匹配;- 在
/root/.cache挂载持久化缓存卷,模型下载结果在 Pod 重启后得以保留; - 配置了
/health的 startup、readiness 与 liveness 三种探针; - 提供内存介质(
emptyDir.medium: Memory)的/dev/shm卷,供 PyTorch 与音频预处理使用。
1. 构建并推送 CPU 镜像
以 API 目录作为 CPU 构建上下文,但 shell 始终停留在仓库根目录:
docker build -f examples/openai_api/Dockerfile -t registry.example.com/speech/funasr-api:cpu-latest examples/openai_api docker push registry.example.com/speech/funasr-api:cpu-latest然后将 kustomization.yaml 中的images替换为你推送的镜像。为了可复现部署,建议将示例的可变 tag 换成你镜像仓库的不可变 digest,并在每次发布前记录镜像 digest 与清单,以便回滚。
CPU Dockerfile 的实现要点
从 Dockerfile 源码可以看到该镜像的构建逻辑:
- 基础镜像为
python:3.10-slim,并通过环境变量固化默认行为:FUNASR_MODEL=sensevoice、FUNASR_DEVICE=cpu、FUNASR_PORT=8000; - 安装
ffmpeg、git、libsndfile1等运行时依赖(音频解码与模型下载所需); - 通过 pip 安装
funasr、fastapi、uvicorn[standard]、python-multipart——注意它从 PyPI 安装 FunASR,而不是安装当前 checkout 里的 FunASR 包; - 仅复制示例
server.py到/app,因此该镜像依赖不是锁定环境,依赖版本会随 PyPI 滚动更新; - 内置 Docker
HEALTHCHECK(每 30s、超时 5s、启动期 60s、重试 3 次),与 Kubernetes 探针互为补充; - 启动命令为
python server.py --host 0.0.0.0 --port ${FUNASR_PORT} --device ${FUNASR_DEVICE} --model ${FUNASR_MODEL},由环境变量驱动。
2. 部署到集群
使用声明式方式创建命名空间并应用 Kustomize 目录:
kubectl create namespace speech --dry-run=client -o yaml | kubectl apply -f - kubectl -n speech apply -k examples/openai_api/kubernetes kubectl -n speech rollout status deploy/funasr-api --timeout=15m
kubectl create namespace ... --dry-run=client -o yaml | kubectl apply -f -是一种幂等的命名空间创建写法,重复执行不会报 "already exists" 错误。
CPU 服务器会在启动 HTTP 之前预加载配置的模型。模型下载与首次加载可能耗时数分钟,因此 startup 探针的失败预算约为 10 分钟(10s周期 ×60次失败,见 funasr-api.yaml 的startupProbe配置);该预算不含镜像拉取、调度和 PVC 绑定耗时。
需要提醒的是:/health返回成功不等于推理可用。从 server.py 的实现看,/health只返回status、device、models_loaded与models_available四个字段,并不执行任何语音识别。因此在下文完成音频请求验证之前,不要对外放行流量。
清单结构速览
funasr-api.yaml 是一个多文档 YAML,包含:
| 资源 | 关键配置 |
|---|---|
PersistentVolumeClaim | 名称funasr-cache,ReadWriteOnce,请求20Gi |
ConfigMap | 注入FUNASR_PORT=8000、FUNASR_DEVICE=cpu、FUNASR_MODEL=sensevoice三个环境变量 |
Deployment | replicas: 1,strategy: Recreate;探针均指向/health;requests: 2 CPU / 8Gi,limits: 16Gi;挂载cache到/root/.cache、dshm(emptyDir.medium: Memory,上限2Gi)到/dev/shm |
Service | type: ClusterIP,port: 8000→targetPort: http |
其中strategy: Recreate与ReadWriteOnce的缓存 PVC 相匹配——同一时间只允许一个 Pod 挂载该卷,滚动更新会先删旧再建新。
3. 冒烟测试
保持服务私有,先通过port-forward验证:
kubectl -n speech port-forward --address 127.0.0.1 svc/funasr-api 8000:8000保持该终端运行,在仓库根目录另开一个终端:
python3 examples/openai_api/smoke_test.py --base-url http://127.0.0.1:8000 --model sensevoice --response-format verbose_jsonsmoke_test.py 的行为细节如下:
- 仅当当前目录缺少
sample.wav时,才会下载公开中文样例(默认地址指向阿里云 OSS 测试音频);若文件已存在则直接复用; - 依次打印
/health、/v1/models以及完整的转写 JSON; - 以 multipart 表单提交
file、model、response_format字段,构造逻辑见其multipart_body函数; - 支持
--base-url、--model、--response-format、--sample-url、--timeout等参数,且各参数均可通过同名环境变量(BASE_URL、MODEL、RESPONSE_FORMAT、SAMPLE_URL、TIMEOUT)注入。
注意:退出码为 0 并不代表识别准确、说话人标签、内存容量或并发能力通过验证。文本与时间戳需要人工检查。同时应避免保留敏感音频或未脱敏的输出。此外,该客户端不发送Authorization头,而安全指南中的转写专用网关会刻意拒绝元数据路由,因此请通过本地port-forward使用本冒烟方案,而不是经由那个网关。
集群内客户端寻址
对于集群内的客户端,直接 HTTP 访问使用:
http://funasr-api.speech.svc.cluster.local:8000作为 OpenAI SDK 的base_url则使用:
http://funasr-api.speech.svc.cluster.local:8000/v1Dify、n8n 或 Web 后端若与 API 同处一个集群,应指向该 Kubernetes 服务名,而不是localhost。
4. 按集群情况调优
下表汇总了原文给出的调优建议,结合清单可进一步定位配置位置:
| 设置项 | 默认值 | 何时修改 |
|---|---|---|
FUNASR_MODEL | sensevoice | 先核对模型的依赖与硬件要求;/v1/models列出的只是别名,并不代表每个模型都已就绪 |
FUNASR_DEVICE | cpu | 仅在构建了 CUDA 镜像并配置好 GPU 调度后才改为cuda |
| PVC 大小 | 20Gi | 需要缓存多个模型或大版本模型时增大(对应 funasr-api.yaml 中 PVC 的storage: 20Gi) |
| 内存 request | 8Gi | 观察启动与实际音频负载后调整(清单中 limits 为16Gi) |
| startup 探针 | 约 10 分钟 | 针对模型初始化调整;镜像拉取、调度、PVC 绑定问题需单独排查 |
模型别名与底层映射关系见 server.py 的MODEL_CONFIGS:例如sensevoice映射到iic/SenseVoiceSmall并附带fsmn-vad与 30 秒单段上限的 VAD 参数;paraformer额外加载ct-punc标点模型;fun-asr-nano从 Hugging Face Hub 加载并开启trust_remote_code。
5. MOSS GPU 替代方案
MOSS-Transcribe-Diarize 是 OpenMOSS-Team 集成进 FunASR 的模型。该清单运行的是打包好的 FunASR HTTP 适配器(verbose_json输出),并非原生 vLLM,也不遵循其diarized_json契约;且说话人标签不构成经过验证的身份信息。关于模型要求、输出格式、无外部 VAD 行为以及其他服务后端,请参考 MOSS 部署指南。
MOSS 清单未包含在kustomization.yaml中,需要单独应用。它申请 1 块 NVIDIA GPU、24Gi 内存、40Gi 缓存 PVC 和 8Gi 的内存/dev/shm(见 funasr-moss-api.yaml);这些是模板设置,不是实测容量承诺。部署前请先配置好集群的 GPU device plugin 与调度。
与 CPU 镜像不同,Dockerfile.moss 会复制并安装整个 checkout(COPY . /opt/funasr+pip install .),因此其构建上下文必须是仓库根目录:
docker build -f examples/openai_api/Dockerfile.moss -t registry.example.com/speech/funasr-api:moss-local . docker push registry.example.com/speech/funasr-api:moss-local要点说明:
- 基础镜像是
pytorch/pytorch:2.9.1-cuda12.8-cudnn9-runtime,并额外安装transformers>=5.6,<6; - 启动命令为
funasr-server --host 0.0.0.0 --port ${FUNASR_PORT} --device ${FUNASR_DEVICE} --model ${FUNASR_MODEL},其中FUNASR_DEVICE默认为cuda:0、FUNASR_MODEL默认为moss-transcribe-diarize; - 构建上下文包含整个仓库,请使用不含凭据或私有数据的干净 checkout。
应用前,将 funasr-moss-api.yaml 中的funasr-moss-api:local替换为已推送镜像的不可变 digest。若跳过了 CPU 部署,请先按第 2 节创建speech命名空间,并保存镜像 digest 与编辑后的清单作为回滚记录:
kubectl -n speech apply -f examples/openai_api/kubernetes/funasr-moss-api.yaml kubectl -n speech rollout status deploy/funasr-moss-api --timeout=15m kubectl -n speech port-forward --address 127.0.0.1 svc/funasr-moss-api 8001:8000在仓库根目录另开终端,使用本地端口 8001 与 CPU 示例保持隔离:
python3 examples/openai_api/smoke_test.py --base-url http://127.0.0.1:8001 --model moss-transcribe-diarize --response-format verbose_jsonMOSS 模板包含 startup 与 readiness 探针,但没有 liveness 探针;其/health响应同样不测试转写能力。请对照自己的音频检查返回文本与说话人分割结果——本方案不承诺特定 GPU 的实时性能或生产负载能力。
6. GPU 部署注意事项
普通 Dockerfile 是 CPU 优先的。仅设置FUNASR_DEVICE=cuda并不会让该镜像变成受支持的 GPU 镜像——还需要 CUDA 运行时、GPU 驱动与调度配置。对于其他 GPU 模型,需要相应调整依赖与调度。
以下字段示意中,resources属于容器(container)级别,而nodeSelector属于 Pod spec 级别,二者并非同一层级、不能直接合并进同一段 YAML:
resources: limits: nvidia.com/gpu: "1" nodeSelector: nvidia.com/gpu.present: "true"确切的 GPU 标签(label)、运行时类(runtime class)与 device plugin 配置因 Kubernetes 发行版而异。在认证、TLS、上传大小限制与速率限制就位之前,请始终保持服务私有。
7. 运维检查清单
- 先查 PVC 绑定、镜像拉取、Pod 事件与模型加载日志,再调整探针预算;随后检查
/health、/v1/models与一次真实音频响应; - 记录模型别名、设备、音频时长、响应格式、延迟与错误文本,便于问题回溯;
- 从单副本起步,因为缓存 PVC 是
ReadWriteOnce;横向扩展需配合注册表镜像、每 Pod 独立缓存或共享只读模型缓存,并先测量内存与启动时间; - 为预期客户端强制认证与 NetworkPolicy——命名空间本身不是网络隔离边界;
- 集群内的 Dify、n8n 或 Web 后端应指向 Kubernetes 服务名而非
localhost。
安全加固补充
SECURITY.md 对 Kubernetes 场景给出了进一步约束,可作为上文清单的延伸:
ClusterIP不会阻止集群内其他 Pod 或可达主机调用该服务,暴露 Ingress/LoadBalancer 前必须先落地 TLS、认证、上传限额与速率限制;- 模型缓存卷应限定在拥有该服务的命名空间或节点池内私有使用;
- 用
NetworkPolicy限制可调用该服务的命名空间; - 首次验证务必走
kubectl port-forward+smoke_test.py,之后再考虑暴露路由; - 若启用 GPU,需固定调度规则,并在部署记录中写明镜像 tag、CUDA 运行时与模型别名。
结语
本文完整覆盖了 FunASR OpenAI 兼容 API 在 Kubernetes 上的部署路径:从保守的 CPU 清单(持久化模型缓存、三探针、/dev/shm内存卷)到面向 MOSS-Transcribe-Diarize 的 GPU 模板,再到集群内寻址、冒烟验证与安全加固。核心要点可以概括为:先本地 port-forward 验证推理,再谈暴露;先补认证与网络策略,再谈公网;先测量内存与启动,再谈扩容。相关清单与脚本均可直接在 examples/openai_api/kubernetes 目录下查看与复用。
【免费下载链接】FunASROpen-source speech recognition toolkit for training, inference, streaming ASR, VAD, punctuation, speaker diarization pipelines, and OpenAI-compatible/MCP serving.项目地址: https://gitcode.com/GitHub_Trending/fun/FunASR
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考