Deploy an internal speech endpoint for agents, web backends, workflow engines, or batch workers. Start with the SenseVoice CPU template; the separate MOSS GPU recipe below adds transcription with speaker diarization.
Run every command from the FunASR repository root, including commands in additional terminals. You need Docker, a writable image registry, kubectl configured for the intended cluster, permission to create resources in speech, and a default StorageClass for the cache PVCs. Replace the example registry before building. The local smoke client requires Python 3.10 or newer, with no third-party Python packages.
ClusterIP is not authentication. Neither manifest supplies a NetworkPolicy, authentication gateway, TLS, or request limits. Review the service security guide before allowing untrusted clients. The recipes below use a local port-forward, not a public ingress.
The manifest is intentionally conservative:
ClusterIPservice by default, not a publicLoadBalancer.FUNASR_DEVICE=cpuby default so the image matches the portable Dockerfile.- A persistent cache volume mounted at
/root/.cacheso model downloads survive pod restarts. /healthstartup, readiness, and liveness probes.- A memory-backed
/dev/shmvolume for PyTorch and audio preprocessing.
Use the API directory as the CPU build context, while keeping your shell at the repository root:
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-latestSet images in examples/openai_api/kubernetes/kustomization.yaml to the pushed image. For reproducible deployments, replace the example mutable tag with your registry's immutable digest. Record the image digest and manifest before each rollout so you can restore them. This CPU Dockerfile copies the example server.py but installs FunASR from PyPI; it does not install the checkout's FunASR package. Its dependencies are not a locked environment.
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=15mThe CPU server preloads its configured model before starting HTTP. Model download and first load can take several minutes. The startup probe has an approximately 10-minute failure budget (10s period, 60 failures); this does not include image pulls, scheduling, or PVC binding. A successful /health response is not an inference check: complete the audio request below before admitting traffic.
Keep the service private and verify it through port-forward first:
kubectl -n speech port-forward --address 127.0.0.1 svc/funasr-api 8000:8000Leave port-forward running. In another terminal at the same repository root:
python3 examples/openai_api/smoke_test.py --base-url http://127.0.0.1:8000 --model sensevoice --response-format verbose_jsonFor in-cluster clients, use http://funasr-api.speech.svc.cluster.local:8000 as the direct HTTP base URL and http://funasr-api.speech.svc.cluster.local:8000/v1 as the OpenAI SDK base URL.
The smoke client downloads a public Chinese sample only if sample.wav is missing in the current directory; an existing file is reused. It prints health, model metadata, and the full transcription JSON. Inspect the text and timestamps yourself: exit status zero does not validate recognition accuracy, speaker labels, memory capacity, or concurrency. Avoid retaining sensitive audio or unredacted output. The client does not send Authorization; the security guide's transcription-only gateway intentionally denies metadata routes, so use this smoke recipe through the local port-forward, not that gateway.
| Setting | Default | When to change it |
|---|---|---|
FUNASR_MODEL |
sensevoice |
Check the model's dependencies and hardware requirements first; /v1/models lists aliases, not proof that each model is ready. |
FUNASR_DEVICE |
cpu |
Set to cuda only after building a CUDA-capable image and configuring GPU scheduling. |
| PVC size | 20Gi |
Increase when caching multiple models or large model revisions. |
| Memory request | 8Gi |
Tune after observing startup and real audio workloads. |
| Startup probe | About 10 minutes | Tune for model initialization; diagnose image pulls, scheduling, and PVC binding separately. |
MOSS-Transcribe-Diarize is an OpenMOSS-Team model integrated into FunASR. This manifest runs the packaged FunASR HTTP adapter with verbose_json, not native vLLM or its diarized_json contract. Diarization labels are not verified speaker identity. For model requirements, outputs, no-external-VAD behavior, and other serving backends, use the MOSS deployment guide.
The MOSS manifest is not included in kustomization.yaml. It requests one NVIDIA GPU, 24Gi memory, a 40Gi cache PVC, and an 8Gi memory-backed /dev/shm; these are template settings, not measured capacity guarantees. Configure the cluster's GPU device plugin and scheduling first. Unlike the CPU image, Dockerfile.moss copies and installs the whole checkout, so its build context must be the repository root. Use a clean checkout without credentials or private data in the build context.
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-localBefore applying, replace funasr-moss-api:local in examples/openai_api/kubernetes/funasr-moss-api.yaml with the pushed image's immutable digest. Create the speech namespace as in step 2 if you skipped the CPU deployment. Save the image digest and edited manifest as your rollback record.
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:8000In another terminal at the repository root, use local port 8001 to keep this endpoint separate from the CPU example:
python3 examples/openai_api/smoke_test.py --base-url http://127.0.0.1:8001 --model moss-transcribe-diarize --response-format verbose_jsonThe MOSS template has startup and readiness probes, but no liveness probe. Its /health response does not test transcription. Review the returned text and diarization against your audio; this recipe does not certify a particular GPU, real-time performance, or production load.
The ordinary Dockerfile is CPU-first. Setting FUNASR_DEVICE=cuda alone does not make it a supported GPU image. For other GPU models, adapt the dependencies and scheduling. In the following field sketch, resources belongs to the container while nodeSelector belongs to the Pod spec; they are not a complete same-level manifest:
resources:
limits:
nvidia.com/gpu: "1"
nodeSelector:
nvidia.com/gpu.present: "true"Exact GPU labels, runtime classes, and device plugin configuration vary by Kubernetes distribution. Keep the service private until authentication, TLS, upload-size limits, and rate limits are in place.
- Check PVC binding, image pulls, Pod events, and model-loading logs before changing probe budgets. Then inspect
/health,/v1/models, and a real audio response. - Log model alias, device, audio duration, response format, latency, and error text.
- Start with one replica because the cache PVC is
ReadWriteOnce; scale horizontally with a registry image, per-pod cache, or a shared read-only model cache after measuring memory and startup time. - Enforce authentication and NetworkPolicy for the intended clients; a namespace alone is not a network isolation boundary.
- For Dify, n8n, or web backends inside the same cluster, point them at the Kubernetes service name instead of
localhost.