Kubernetes上跑PHP视频处理,弹性伸缩这件事,说难也难,说简单也简单——关键不在于语言本身,而在于你舍得把“调度”和“干活”拆开。PHP只管调度和元数据管理,真正的编解码、模型推理,必须交给FFmpeg、WAN2.2这类专用Worker。搞清楚了这一点,后面的HPA配置、GPU隔离、存储选择,才能对路。

先说一句:千万别指望PHP自己碰视频帧。很多团队上来就把exec('ffmpeg -i ...')塞进PHP-FPM里跑,结果一个请求卡住好几秒,FPM子进程直接夯死,CPU打满但实际干的活全是阻塞。WAN2.2这类模型更不能直连PHP,显存爆掉就是一眨眼的事。
PHP只负责调度,别让它碰视频帧
- PHP应用应该退到控制平面:接收上传、校验格式、写入任务队列(比如RabbitMQ或Kafka)、返回一个任务ID给前端。
- 真实的转码或视频生成任务,交给独立的Job或Deployment执行。可以用
initContainers预加载模型或缓存,主容器只调ffmpeg或python inference.py。 - 如果确实需要PHP做轻量处理(比如截图、抽帧),记得改用
proc_open()并设好超时和资源限制,别让它阻塞整个FPM进程池。
HPA扩缩容必须基于真实负载指标
一个常见的坑:kubectl top pod显示CPU 30%,但PHP容器其实是在等FFmpeg子进程结束——这算哪门子有效负载?如果HPA只盯CPU,就会误判:视频任务排队时PHP闲着,HPA不扩容;FFmpeg密集跑时PHP又没占多少CPU,HPA还是没反应。
- 最优方案:用自定义指标。通过Prometheus抓取
queue_length(比如Redis的pending count)或task_pending_total(RoadRunner暴露的rr_http_requests_queue_size)。 - 如果只能靠资源指标,给PHP容器设
resources.requests.cpu: 200m,同时给FFmpeg Worker的Deployment单独配一个HPA,目标指标用container_cpu_usage_seconds_total。 - 别忘了调整
beha vior.scaleUp.stabilizationWindowSeconds。视频任务启动慢——加载模型可能就要10秒以上——把这个值设成60秒,避免刚扩容的Pod因为还没跑出负载就被HPA误判为“无效”而删掉。
GPU资源隔离与节点亲和性必须显式声明
WAN2.2或CUDA加速的FFmpeg需要GPU,但PHP Web层不需要。默认调度下,PHP Pod很可能被挤到GPU节点上,白白浪费资源还抢占显存。
- 给GPU Worker加
nodeSelector:nvidia.com/gpu: "1",并配taints防止PHP Pod误调度过去。 - PHP Deployment反过来加
tolerations排除GPU节点,或者直接用nodeAffinity限定到CPU-only节点池。 - 注意StorageClass:视频临时文件要用
ReadWriteMany(比如NFS),别用默认的ReadWriteOnce,否则多Worker无法共享输入输出路径。
失败重试与断点续传不能靠PHP自己扛
一个5分钟的视频转码,中途Pod被HPA缩容或者节点故障,PHP如果只记“任务开始”,任务直接就丢了。Kubernetes原生并不保证Job一次成功。
- 用
Job而非Pod跑视频任务,设backoffLimit: 3,失败自动重试。 - 任务状态存到外部存储(如MySQL/PostgreSQL),PHP只负责读状态,Worker负责写;千万别用PHP session或本地文件存进度。
- 长任务加
activeDeadlineSeconds: 1800(30分钟),防止Worker卡死无限占用GPU。
真正难的不是写YAML,而是厘清边界:PHP管什么、Worker管什么、K8s管什么。视频文件一动就是GB级别,调度错一层,磁盘IO、网络带宽、GPU显存全跟着错。别指望HPA能自动适配所有场景——它只响应你喂给它的指标。喂错了,扩缩容就变成了随机行为。
