php不直接转码,而是通过消息队列将任务交由独立部署的ffmpeg worker pod处理;worker需设非root权限、资源限制、挂载卷权限及按队列积压扩缩容。

PHP本身不干转码的活,它只负责把任务扔进Kubernetes集群,让FFmpeg在Worker Pod里真正干活。直接在PHP进程里调用exec()跑FFmpeg,高并发下必崩。
为什么不能在PHP容器里直接跑FFmpeg
PHP-FPM容器是为处理HTTP请求设计的,不是音视频工作站。强行在里面启动FFmpeg会导致:
-
max_execution_time和memory_limit频繁触发,转码中途被杀 - PHP-FPM子进程卡死,整个Web服务响应变慢甚至502
- CPU使用率飙升后,K8s的
livenessProbe误判Pod异常,反复重启 - 无法限制单个转码任务的CPU/内存配额,一个大文件可能拖垮整个Node
FFmpeg Worker Pod必须独立部署
转码Worker不能和PHP应用混在同一个Deployment里。正确做法是用单独的Deployment部署FFmpeg镜像,并通过消息队列解耦。
- Worker镜像基于
ubuntu:22.04或debian:bookworm-slim,预装ffmpeg5.1+(支持H.265)和ffprobe - Pod资源限制必须硬性设置:
resources.limits.cpu: "2"、resources.limits.memory: "4Gi" - 启动命令不是
ffmpeg -i ...,而是运行一个监听RabbitMQ或Redis队列的PHP CLI脚本 - 该脚本从队列取任务后,用
proc_open()调用FFmpeg,并实时捕获stderr解析进度(如frame= 1234)
K8s中PHP与Worker的通信链路
PHP应用只做三件事:存文件、发消息、查状态。所有耗时操作都移交出去。
- 用户上传视频后,PHP将文件存入对象存储(如MinIO),并写入数据库记录
source_url和job_id - PHP向
transcode_queue推送JSON消息:{"job_id":"abc123","source":"minio://bucket/input.mp4","profiles":[{"format":"hls","resolution":"1280x720","bitrate":"1500k"}]} - Worker消费后,执行类似命令:
ffmpeg -i "minio://bucket/input.mp4" -c:v libx264 -b:v 1500k -s 1280x720 -f hls -hls_time 4 /output/abc123_720p.m3u8 - 转码完成后,Worker更新数据库
status字段,并触发PHP的Webhook回调
容易被忽略的K8s配置细节
Worker Pod跑得稳,关键在几个不起眼但致命的配置项:
- 必须设置
securityContext.runAsNonRoot: true和runAsUser: 1001,否则FFmpeg可能因权限问题无法写入挂载卷 - 挂载的持久卷(如NFS或hostPath)要设
fsGroup: 1001,确保Worker能读写输出目录 - 不要用
hostNetwork: true——FFmpeg不需要绑定宿主机端口,反而会引发端口冲突 - HPA不能按CPU扩缩Worker,而应按队列积压长度(如RabbitMQ的
queue_messages_ready指标)
真正的瓶颈从来不在PHP代码里,而在Pod资源限制是否贴合FFmpeg的实际内存峰值、消息队列是否丢任务、以及对象存储的IO吞吐能否跟上多路并发写入。这些地方一松动,整个转码流水线就断在最意想不到的位置。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











